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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20