/[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 2078 - (show annotations) (download)
Sat Nov 23 11:00:41 2013 UTC (10 years, 5 months ago) by torben
File size: 12099 byte(s)
Better handling of null tritstation values
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 int tritStation = res.getInt(11);
60 if (res.wasNull()) {
61 tritStation = -1;
62 }
63 station.setTritStation( tritStation );
64
65 return station;
66 }
67
68 private StationBean convertResultset(ResultSet res) throws SQLException {
69 StationBean stations = new StationBean();
70 while (res.next()) {
71 stations.entries.add( convertSingleRow(res) );
72 }
73 return stations;
74
75 }
76
77 private StationBean fetchStations(String SQL, StatementParamSetter setter) throws SQLException {
78 StationBean stations;
79 Connection conn = null;
80 PreparedStatement stmt = null;
81 ResultSet res = null;
82 try {
83 conn = DBConnection.getConnection();
84 stmt = conn.prepareStatement(SQL);
85
86 setter.setParams(stmt);
87
88 res = stmt.executeQuery();
89 stations = convertResultset(res);
90
91 } finally {
92 if (res != null)
93 res.close();
94 if (stmt != null)
95 stmt.close();
96 if (conn!= null)
97 conn.close();
98 }
99 return stations;
100
101 }
102
103 public StationEntry getById(int id) throws SQLException,NostationException {
104 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog,stationcode_metro,address,0.0,aliases,tritstation " +
105 "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 }
115
116
117
118 /*
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 * create operator ~~~ (procedure = rlike, leftarg = text, rightarg = text, commutator = ~~);
123 */
124 public StationBean getByNameNormal(final String name) throws SQLException {
125 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0,aliases,tritstation " +
126 "FROM trainstations " +
127 "WHERE (name ILIKE ? OR ? ~~~ ANY(aliases)) AND enabled = true " +
128 "ORDER BY name ";
129
130 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 }
137
138 return fetchStations(SQL, new NameSetter() );
139 }
140
141
142 public StationBean getByNameFuzzy(final String name) throws SQLException {
143 String SQL = "SELECT * FROM (" +
144 " SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0, aliases, tritstation, " +
145 " 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
152 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 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 public StationBean getByName(String name) throws SQLException {
173 name = removeSuffix(name, " st.");
174 name = removeSuffix(name, " st");
175 name = removeSuffix(name, " station");
176
177 StationBean stations = getByNameNormal(name);
178
179 if (stations.entries.size() == 0) {
180 stations = getByNameFuzzy(name);
181
182 logger.info("getByName failover: " + name + "(" + (stations.entries.size() >0) + ")" );
183 }
184 return stations;
185 }
186
187
188
189 //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 // 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 // in denmark 0.4dg latitude ~ 44km, 0.75dg longitude ~ 47km
196
197 // 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 // sqrt( power(abs(latitude-?)*111320, 2) + power(abs(longitude-?)*63000,2) )::int as calcdist
201
202 public StationBean getByLocationWorker(final double latitude, final double longitude, final boolean geolimit) throws SQLException {
203
204 String limitExpression = (geolimit == true) ? "AND abs(latitude-?)<0.4 AND abs(longitude-?)<0.75 " : "";
205
206 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, " +
207 "earth_distance( earth_coord, ll_to_earth(?,?))::int AS calcdist,aliases,tritstation " +
208 "FROM trainstations " +
209 "WHERE enabled = true " + limitExpression +
210 "ORDER BY calcdist ASC " +
211 "LIMIT " + LOCATION_LIMIT;
212
213
214 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
226 return fetchStations(SQL, new LatlongSetter() );
227 }
228
229 public StationBean getByLocation(double latitude, double longitude) throws SQLException {
230 StationBean result = getByLocationWorker(latitude, longitude, true);
231
232 if (result.entries.size() < LOCATION_LIMIT) { //failover
233 logger.info("getByLocation failover: " +latitude + "," + longitude);
234
235 result = getByLocationWorker(latitude, longitude, false);
236 }
237
238 return result;
239 }
240
241
242
243 public StationBean getByList(String list) throws SQLException {
244 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog,stationcode_metro, address,0.0,aliases,tritstation " +
245 "FROM trainstations " +
246 "WHERE id IN " + list + " AND enabled = true " +
247 "ORDER BY name ";
248
249 return fetchStations(SQL, new NullSetter() );
250 }
251
252
253
254 public StationEntry getSimpleByName(final String name) throws SQLException {
255 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog, stationcode_metro, address, 0.0,aliases,tritstation " +
256 "FROM trainstations " +
257 "WHERE name = ? AND enabled = true " +
258 "LIMIT 1 ";
259
260 class NameSetter implements StatementParamSetter {
261 @Override
262 public void setParams(PreparedStatement stmt) throws SQLException {
263 stmt.setString(1, name );
264 }
265 }
266
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
276 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 //used to create full dump in order to populate Google Appengine DB
284 //after 1.1.0 also used to populate client-side station list
285 public StationBean dumpAll() throws SQLException {
286
287 String SQL = "SELECT id,name,latitude,longitude,stationcode_fjrn,stationcode_stog,stationcode_metro,address,0.0,aliases,tritstation " +
288 "FROM trainstations WHERE enabled = true";
289
290
291 StationBean stations = fetchStations(SQL, new NullSetter() );
292 Collections.sort( stations.entries,nameComparator );
293
294 return stations;
295
296 /*
297 Connection conn = null;
298 Statement stmt = null;
299 ResultSet res = null;
300
301
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 Collections.sort( stations.entries,nameComparator );
323 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 }*/
334
335 }
336
337 /*
338 @Deprecated
339 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 try {
354 if (conn != null && !conn.isClosed())
355 conn.close();
356 } catch (Exception e) {}
357 }
358
359 return station;
360 }*/
361
362 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
380 /*
381 @Deprecated
382 public int getIdByName(final String name) throws SQLException {
383 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
388 class NameSetter implements StatementParamSetter {
389 @Override
390 public void setParams(PreparedStatement stmt) throws SQLException {
391 stmt.setString(1, name );
392 }
393 }
394
395 StationBean stations = fetchStations(SQL, new NameSetter() );
396
397 if (stations.entries.size() == 1) {
398 return stations.entries.get(0).getId();
399 } else {
400 return -1;
401 }
402 }*/
403 }

  ViewVC Help
Powered by ViewVC 1.1.20