/[projects]/android/TrainInfoService/src/dk/thoerup/traininfoservice/db/StationDAO.java
ViewVC logotype

Contents of /android/TrainInfoService/src/dk/thoerup/traininfoservice/db/StationDAO.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1832 - (show annotations) (download)
Mon Aug 20 21:15:37 2012 UTC (11 years, 8 months ago) by torben
File size: 12074 byte(s)
First attempt at tritinfo integration
1 package dk.thoerup.traininfoservice.db;
2
3 import java.sql.Array;
4 import java.sql.Connection;
5 import java.sql.PreparedStatement;
6 import java.sql.ResultSet;
7 import java.sql.SQLException;
8 import java.sql.Statement;
9 import java.util.Collections;
10 import java.util.Comparator;
11 import java.util.logging.Logger;
12
13 import dk.thoerup.android.traininfo.common.StationBean;
14 import dk.thoerup.android.traininfo.common.StationEntry;
15
16 public class StationDAO {
17
18 private interface StatementParamSetter {
19 public void setParams(PreparedStatement stmt) throws SQLException ;
20 }
21 private class NullSetter implements StatementParamSetter {
22 @Override
23 public void setParams(PreparedStatement stmt) throws SQLException {}
24 }
25
26 public static class NostationException extends Exception {
27 private static final long serialVersionUID = 1L;
28 }
29
30 final static int LOCATION_LIMIT = 8;
31 static final Logger logger = Logger.getLogger(StationDAO.class.getName());
32
33
34 private StationEntry convertSingleRow(ResultSet res) throws SQLException {
35 StationEntry station = new StationEntry();
36
37 station.setId( res.getInt(1) );
38 station.setName( res.getString(2) );
39 station.setLatitude( res.getDouble(3) );
40 station.setLongitude( res.getDouble(4) );
41 station.setRegional( res.getString(5) );
42 station.setStrain( res.getString(6) );
43 station.setMetro( res.getString(7) );
44 station.setAddress( res.getString(8) );
45 station.setCalcdist( (int)res.getDouble(9) );
46
47 station.setIsRegional( station.getRegional() != null );
48 station.setIsStrain( station.getStrain() != null );
49 station.setIsMetro( station.getMetro() != null );
50
51 Array aliases = res.getArray( 10);
52 if (aliases != null) {
53 station.setAliases( (String[]) aliases.getArray() );
54 } else {
55 String[] emptyArray = {};
56 station.setAliases( emptyArray );
57 }
58
59 station.setTritStation( res.getInt(11) );
60 if (res.wasNull())
61 station.setTritStation( -1 );
62
63 return station;
64 }
65
66 private StationBean convertResultset(ResultSet res) throws SQLException {
67 StationBean stations = new StationBean();
68 while (res.next()) {
69 stations.entries.add( convertSingleRow(res) );
70 }
71 return stations;
72
73 }
74
75 private StationBean fetchStations(String SQL, StatementParamSetter setter) throws SQLException {
76 StationBean stations;
77 Connection conn = null;
78 PreparedStatement stmt = null;
79 ResultSet res = null;
80 try {
81 conn = DBConnection.getConnection();
82 stmt = conn.prepareStatement(SQL);
83
84 setter.setParams(stmt);
85
86 res = stmt.executeQuery();
87 stations = convertResultset(res);
88
89 } finally {
90 if (res != null)
91 res.close();
92 if (stmt != null)
93 stmt.close();
94 if (conn!= null)
95 conn.close();
96 }
97 return stations;
98
99 }
100
101 public StationEntry getById(int id) throws SQLException,NostationException {
102 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog,stationcode_metro,address,0.0,aliases,tritstation " +
103 "FROM trainstations WHERE id=" + id + " AND enabled=true";
104
105 StationBean stations = fetchStations(SQL, new NullSetter() );
106
107 if (stations.entries.size() > 0 ) {
108 return stations.entries.get(0);
109 } else {
110 throw new NostationException();
111 }
112 }
113
114
115
116 /*
117 * this code requires theses statements are run on database in order to do ILIKE searches against aliases (which is defines as array of varchar(64) )
118 * create function rlike(text,text) returns bool as
119 * 'select $2 ilike $1' language sql strict immutable;
120 * create operator ~~~ (procedure = rlike, leftarg = text, rightarg = text, commutator = ~~);
121 */
122 public StationBean getByNameNormal(final String name) throws SQLException {
123 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0,aliases,tritstation " +
124 "FROM trainstations " +
125 "WHERE (name ILIKE ? OR ? ~~~ ANY(aliases)) AND enabled = true " +
126 "ORDER BY name ";
127
128 class NameSetter implements StatementParamSetter {
129 @Override
130 public void setParams(PreparedStatement stmt) throws SQLException {
131 stmt.setString(1, name + "%");
132 stmt.setString(2, name + "%");
133 }
134 }
135
136 return fetchStations(SQL, new NameSetter() );
137 }
138
139
140 public StationBean getByNameFuzzy(final String name) throws SQLException {
141 String SQL = "SELECT * FROM (" +
142 " SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0, aliases, tritstation, " +
143 " levenshtein(lower(name),lower(?) ) as leven " +
144 " FROM trainstations " +
145 " WHERE enabled = true ) as lev2 " +
146 "WHERE (leven <= 3) " +
147 "ORDER BY leven " +
148 "LIMIT 1";
149
150 class NameSetter implements StatementParamSetter {
151 @Override
152 public void setParams(PreparedStatement stmt) throws SQLException {
153 stmt.setString(1, name );
154 }
155 }
156
157 StationBean stations = fetchStations(SQL, new NameSetter() );
158 stations.fuzzystrmatch = true;
159 return stations;
160 }
161
162 private String removeSuffix(String str, String suffix) {
163 if (str.endsWith(suffix)) {
164 return str.substring(0, str.length() - suffix.length() );
165 } else {
166 return str;
167 }
168 }
169
170 public StationBean getByName(String name) throws SQLException {
171 name = removeSuffix(name, " st.");
172 name = removeSuffix(name, " st");
173 name = removeSuffix(name, " station");
174
175 StationBean stations = getByNameNormal(name);
176
177 if (stations.entries.size() == 0) {
178 stations = getByNameFuzzy(name);
179
180 logger.info("getByName failover: " + name + "(" + (stations.entries.size() >0) + ")" );
181 }
182 return stations;
183 }
184
185
186
187 //Latitude (horizonal), longitude(vertical) so
188 // 1 degree latitude is ~ 111320 meters, since the distance between the horizonal lines is always the same
189 // 1 degree longitude is ~111320 meters at equator but gets shorter as we get closer to the poles.
190 // so 1 degree longitude is 64.5 km at denmarks southern point (gedser=54.55,11.95)
191 // and is 59.4km at northern point (skagen = 57.75,10.65)
192 // The "hack" with max 0.4 degrees latitude and 0.75 degrees longitude is only valid since we only service danish trains,
193 // in denmark 0.4dg latitude ~ 44km, 0.75dg longitude ~ 47km
194
195 // the ultra fast method (and only slightly inaccurate as long as we only cover a limited geographically area)
196 // is using an aproximation of the length of 1 latitude degree and 1 longitude degree and just use pythagoras to
197 // calculate the distance:
198 // sqrt( power(abs(latitude-?)*111320, 2) + power(abs(longitude-?)*63000,2) )::int as calcdist
199
200 public StationBean getByLocationWorker(final double latitude, final double longitude, final boolean geolimit) throws SQLException {
201
202 String limitExpression = (geolimit == true) ? "AND abs(latitude-?)<0.4 AND abs(longitude-?)<0.75 " : "";
203
204 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, " +
205 "earth_distance( earth_coord, ll_to_earth(?,?))::int AS calcdist,aliases,tritstation " +
206 "FROM trainstations " +
207 "WHERE enabled = true " + limitExpression +
208 "ORDER BY calcdist ASC " +
209 "LIMIT " + LOCATION_LIMIT;
210
211
212 class LatlongSetter implements StatementParamSetter {
213 @Override
214 public void setParams(PreparedStatement stmt) throws SQLException {
215 stmt.setDouble(1, latitude);
216 stmt.setDouble(2, longitude);
217 if (geolimit == true) {
218 stmt.setDouble(3, latitude);
219 stmt.setDouble(4, longitude);
220 }
221 }
222 }
223
224 return fetchStations(SQL, new LatlongSetter() );
225 }
226
227 public StationBean getByLocation(double latitude, double longitude) throws SQLException {
228 StationBean result = getByLocationWorker(latitude, longitude, true);
229
230 if (result.entries.size() < LOCATION_LIMIT) { //failover
231 logger.info("getByLocation failover: " +latitude + "," + longitude);
232
233 result = getByLocationWorker(latitude, longitude, false);
234 }
235
236 return result;
237 }
238
239
240
241 public StationBean getByList(String list) throws SQLException {
242 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog,stationcode_metro, address,0.0,aliases,tritstation " +
243 "FROM trainstations " +
244 "WHERE id IN " + list + " AND enabled = true " +
245 "ORDER BY name ";
246
247 return fetchStations(SQL, new NullSetter() );
248 }
249
250
251
252 public StationEntry getSimpleByName(final String name) throws SQLException {
253 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0,aliases,tritstation " +
254 "FROM trainstations " +
255 "WHERE name = ? AND enabled = true " +
256 "LIMIT 1 ";
257
258 class NameSetter implements StatementParamSetter {
259 @Override
260 public void setParams(PreparedStatement stmt) throws SQLException {
261 stmt.setString(1, name );
262 }
263 }
264
265 StationBean stations = fetchStations(SQL, new NameSetter() );
266
267 if (stations.entries.size() == 1) {
268 return stations.entries.get(0);
269 } else {
270 return null;
271 }
272 }
273
274 Comparator<StationEntry> nameComparator = new Comparator<StationEntry>() {
275 @Override
276 public int compare(StationEntry arg0, StationEntry arg1) {
277 return arg0.getName().compareTo( arg1.getName() );
278 }
279 };
280
281 //used to create full dump in order to populate Google Appengine DB
282 //after 1.1.0 also used to populate client-side station list
283 public StationBean dumpAll() throws SQLException {
284
285 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog,stationcode_metro,address,0.0,aliases,tritstation " +
286 "FROM trainstations WHERE enabled = true";
287
288
289 StationBean stations = fetchStations(SQL, new NullSetter() );
290 Collections.sort( stations.entries,nameComparator );
291
292 return stations;
293
294 /*
295 Connection conn = null;
296 Statement stmt = null;
297 ResultSet res = null;
298
299
300 try {
301 conn = DBConnection.getConnection();
302
303 stmt = conn.createStatement();
304 res = stmt.executeQuery(SQL);
305
306 // Does mostly the same as convertResultset()
307 StationBean stations = new StationBean();
308 while (res.next()) {
309 StationEntry entry = convertSingleRow(res);
310
311 Array arr = res.getArray(10);
312 if (arr != null) {
313 String[] aliases = (String[]) arr.getArray();
314 entry.setAliases(aliases);
315 }
316
317 stations.entries.add( entry );
318
319 }
320 Collections.sort( stations.entries,nameComparator );
321 return stations;
322
323
324 } finally {
325 if (res != null)
326 res.close();
327 if (stmt != null)
328 stmt.close();
329 if (conn != null)
330 conn.close();
331 }*/
332
333 }
334
335 /*
336 @Deprecated
337 public static String getStationName(int stationID) {
338 String station = "";
339
340 Connection conn = null;
341 try {
342 conn = DBConnection.getConnection();
343 Statement stmt = conn.createStatement();
344 ResultSet rs = stmt.executeQuery("SELECT name FROM trainstations WHERE id=" + stationID);
345 if (rs.next()) {
346 station = rs.getString(1);
347 }
348
349 } catch (Exception e) {
350 } finally {
351 try {
352 if (conn != null && !conn.isClosed())
353 conn.close();
354 } catch (Exception e) {}
355 }
356
357 return station;
358 }*/
359
360 public boolean hasDisabledStation(final String name) throws SQLException {
361 String SQL = "Select count(*) as antal from trainstations where name = '" + name + "' and enabled=false " ;
362
363 Connection conn = DBConnection.getConnection();
364 Statement stmt = conn.createStatement();
365 ResultSet rs = stmt.executeQuery( SQL );
366
367 rs.next();
368
369 int antal = rs.getInt(1);
370
371 rs.close();
372 stmt.close();
373 conn.close();
374
375 return (antal > 0);
376 }
377
378 /*
379 @Deprecated
380 public int getIdByName(final String name) throws SQLException {
381 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0 " +
382 "FROM trainstations " +
383 "WHERE name = ? AND enabled = true " +
384 "LIMIT 1 ";
385
386 class NameSetter implements StatementParamSetter {
387 @Override
388 public void setParams(PreparedStatement stmt) throws SQLException {
389 stmt.setString(1, name );
390 }
391 }
392
393 StationBean stations = fetchStations(SQL, new NameSetter() );
394
395 if (stations.entries.size() == 1) {
396 return stations.entries.get(0).getId();
397 } else {
398 return -1;
399 }
400 }*/
401 }

  ViewVC Help
Powered by ViewVC 1.1.20