/[projects]/android/TrainInfoServiceGoogle/src/dk/thoerup/traininfoservice/banedk/TimetableFetcher.java
ViewVC logotype

Contents of /android/TrainInfoServiceGoogle/src/dk/thoerup/traininfoservice/banedk/TimetableFetcher.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1093 - (show annotations) (download)
Tue Sep 21 20:10:46 2010 UTC (13 years, 7 months ago) by torben
File size: 8036 byte(s)
Code Sync (use jsr107 / memcache for caching)
1 package dk.thoerup.traininfoservice.banedk;
2
3
4
5 import java.net.URL;
6 import java.sql.SQLException;
7 import java.util.HashMap;
8 import java.util.Map;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11
12 import net.sf.jsr107cache.Cache;
13 import net.sf.jsr107cache.CacheException;
14 import net.sf.jsr107cache.CacheManager;
15
16 import org.jsoup.nodes.Document;
17 import org.jsoup.nodes.Element;
18 import org.jsoup.select.Elements;
19
20 import com.google.appengine.api.memcache.jsr107cache.GCacheFactory;
21
22 import dk.thoerup.android.traininfo.common.TimetableBean;
23 import dk.thoerup.android.traininfo.common.TimetableEntry;
24 import dk.thoerup.circuitbreaker.CircuitBreaker;
25 import dk.thoerup.circuitbreaker.CircuitBreakerManager;
26 import dk.thoerup.traininfoservice.StationDAO;
27 import dk.thoerup.traininfoservice.Statistics;
28
29 public class TimetableFetcher {
30
31
32 Cache cache;
33 Cache stationCache;
34
35 StationDAO stationDao = new StationDAO();
36
37
38 Logger logger = Logger.getLogger(TimetableFetcher.class.getName());
39
40 private boolean useAzureSite;
41 private int replyTimeout;
42
43 @SuppressWarnings("unchecked")
44 public TimetableFetcher(boolean azureSite, int cacheTimeout, int replyTimeout) {
45 useAzureSite = azureSite;
46 this.replyTimeout = replyTimeout;
47
48 Map props = new HashMap();
49 props.put(GCacheFactory.EXPIRATION_DELTA_MILLIS, cacheTimeout);
50
51 try {
52 cache = CacheManager.getInstance().getCacheFactory().createCache(props);
53 } catch (CacheException e) {
54 logger.log(Level.WARNING, "error creating cache", e);
55 }
56
57 props = new HashMap();
58 props.put(GCacheFactory.EXPIRATION_DELTA_MILLIS, 3*60*60*1000);
59
60 try {
61 stationCache = CacheManager.getInstance().getCacheFactory().createCache(props);
62 } catch (CacheException e) {
63 logger.log(Level.WARNING, "error creating cache", e);
64 }
65 }
66
67
68 TimetableBean cachedLookupTimetable(String trainID, String type) throws Exception {
69 String key = trainID+type;
70 TimetableBean list = cache.get(key);
71
72 if (list == null) {
73 list = lookupTimetable(trainID,type);
74 cache.put(key, list);
75 } else {
76 Statistics.getInstance().incrementTimetableCacheHits();
77 logger.info("Timetable: Cache hit " + trainID);
78 }
79 return list;
80 }
81
82 TimetableBean lookupTimetable(String trainID, String type) throws Exception {
83 if (useAzureSite == true ){
84 return lookupTimetableAzureSite(trainID, type);
85
86 } else {
87 return lookupTimetableWwwSite(trainID, type);
88 }
89 }
90
91 int getStationId(String name) {
92 Integer id = stationCache.get(name);
93
94 if (id == null) {
95 try {
96 id = stationDao.getIdByName(name);
97 stationCache.put(name, id);
98 } catch (SQLException e) {
99 logger.log(Level.SEVERE, "getStationId failed", e);
100 id = -1;
101 }
102 }
103
104 return id;
105 }
106
107 TimetableBean lookupTimetableAzureSite(String trainID, String type) throws Exception {
108 TimetableBean timetableBean = new TimetableBean();
109
110
111 String url = "http://trafikinfo.bane.dk/TrafikInformation/Ruteplan/" + trainID;
112 logger.fine("URL:" + url);
113
114 JsoupInvocation wrapper = new JsoupInvocation( new URL(url) , replyTimeout);
115 CircuitBreaker breaker = CircuitBreakerManager.getManager().getCircuitBreaker("banedk");
116
117 Document doc = (Document) breaker.invoke(wrapper);
118
119
120 boolean currentStation = false;
121 boolean currentStationSaved = false;
122
123 Elements tables = doc.getElementsByClass("Rute");
124
125 if (tables.size() == 1) {
126 Element timetable = tables.get(0);
127 Elements rows = timetable.getElementsByTag("tr");
128
129 for (int i=0; i<rows.size(); i++) {
130 if (i==0) //First row is column headers
131 continue;
132
133
134 Element row = rows.get(i);
135 Elements fields = row.getElementsByTag("td");
136
137
138 if (currentStationSaved == false && fields.get(0).attr("class").equalsIgnoreCase("Tidsstreg")) {
139 currentStation = true;
140 continue;
141 }
142
143 TimetableEntry entry = new TimetableEntry();
144
145 String station = fields.get(0).text() ;
146 if (station.equals("København"))
147 station = "København H"; //correct inconsistency in naming
148
149 entry.setStation( station );
150 entry.setArrival( fields.get(1).text() );
151 entry.setDeparture( fields.get(2).text() );
152
153 boolean cancelled = fields.get(3).text().equalsIgnoreCase("aflyst");
154 entry.setCancelled(cancelled);
155
156 if (currentStation == true && currentStationSaved == false ) {
157 entry.setCurrent(currentStation);
158 currentStationSaved = true;
159 }
160
161 entry.setStationId( getStationId( station ));
162
163 timetableBean.entries.add(entry);
164 }
165
166 //TODO: There is an off-by-one error in this cancelled parser thingie
167 final String cancelledString = "Aflyst";
168 for (int i=0;i<timetableBean.entries.size(); i++) { //handle cancelled labels
169 final int lastIdx = (timetableBean.entries.size() - 1);
170
171 TimetableEntry current = timetableBean.entries.get(i);
172 if (current.isCancelled()) {
173 if (i == 0) {
174 current.setDeparture(cancelledString);
175 } else if (i == lastIdx) {
176 current.setArrival(cancelledString);
177 } else if (i>0 && i<lastIdx) {
178 TimetableEntry next = timetableBean.entries.get(i+1);
179 TimetableEntry prev = timetableBean.entries.get(i-1);
180
181 if (next.isCancelled())
182 current.setDeparture(cancelledString);
183 if (prev.isCancelled())
184 current.setArrival(cancelledString);
185 }
186 }
187 }
188
189 } else {
190 logger.warning("No time table found, trainID=" + trainID + " type=" + type);
191 }
192
193
194 return timetableBean;
195 }
196
197 TimetableBean lookupTimetableWwwSite(String trainID, String type) throws Exception {
198 TimetableBean timetableBean = new TimetableBean();
199
200 String url = "http://www.bane.dk/visRute.asp?W=" + type + "&TogNr=" + trainID + "&artikelId=4276";
201 logger.fine("URL:" + url);
202
203
204 JsoupInvocation wrapper = new JsoupInvocation( new URL(url) , replyTimeout);
205 CircuitBreaker breaker = CircuitBreakerManager.getManager().getCircuitBreaker("banedk");
206
207 Document doc = (Document) breaker.invoke(wrapper);
208
209
210 boolean currentStation = false;
211 boolean currentStationSaved = false;
212
213 Elements tables = doc.getElementsByClass("Rute");
214
215 if (tables.size() == 1) {
216 Element timetable = tables.get(0);
217 Elements rows = timetable.getElementsByTag("tr");
218
219 for (int i=0; i<rows.size(); i++) {
220 if (i==0) //First row is column headers
221 continue;
222
223
224 Element row = rows.get(i);
225 Elements fields = row.getElementsByTag("td");
226
227
228 if (currentStationSaved == false && fields.get(0).attr("class").equalsIgnoreCase("Tidsstreg")) {
229 currentStation = true;
230 continue;
231 }
232
233 TimetableEntry entry = new TimetableEntry();
234
235 String station = DepartureFetcher.cleanText( fields.get(0).text() ) ;
236 if (station.equals("København"))
237 station = "København H"; //correct inconsistency in naming
238
239 String arrival = DepartureFetcher.cleanText( fields.get(1).text() );
240 String departure = DepartureFetcher.cleanText( fields.get(2).text() );
241
242 entry.setStation( station );
243 entry.setArrival( arrival );
244 entry.setDeparture( departure );
245
246
247 if (currentStation == true && currentStationSaved == false ) {
248 entry.setCurrent(currentStation);
249 currentStationSaved = true;
250 }
251
252 entry.setStationId( getStationId( station ));
253
254 timetableBean.entries.add(entry);
255 }
256
257 } else {
258 logger.warning("No time table found, trainID=" + trainID + " type=" + type);
259 }
260
261
262 return timetableBean;
263 }
264
265 }

  ViewVC Help
Powered by ViewVC 1.1.20