source: osm/applications/editors/josm/wmsadapter/orthofotos-bern/src/ch/guggis/josm/bern/servlet/OrthofotoBernWMSAdapter.java@ 18628

Last change on this file since 18628 was 18628, checked in by guggis, 15 years ago

typo

File size: 18.5 KB
Line 
1package ch.guggis.josm.bern.servlet;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.io.OutputStream;
6import java.io.PrintWriter;
7import java.net.HttpURLConnection;
8import java.net.MalformedURLException;
9import java.net.URL;
10import java.net.URLConnection;
11import java.util.HashMap;
12import java.util.logging.Level;
13import java.util.logging.Logger;
14
15import javax.servlet.ServletException;
16import javax.servlet.http.HttpServlet;
17import javax.servlet.http.HttpServletRequest;
18import javax.servlet.http.HttpServletResponse;
19
20import ch.guggis.josm.bern.servlet.exception.IllegalParameterValueException;
21import ch.guggis.josm.bern.servlet.exception.MissingParameterException;
22import ch.guggis.josm.bern.servlet.exception.OrthofotoBernWMSAdapterException;
23
24/**
25 * This servlet adapts the Web Map Service (WMS) of the city of Bern for the
26 * JOSM WMS plugin.
27 *
28 * It converts lat/lon coordinates (EPSG:4326) used in JOSM to x/y-coordinates
29 * in the Swiss Grid (CH1903).
30 *
31 * The servlet includes methods for retrieving two cookies from the WMS server
32 * of the city of Bern:
33 * <ul>
34 * <li>{@see #COOKIE_NAME_SESSION_ID1} is the cookie generated by the main map
35 * site www.stadthplan.bern.ch</li>
36 * <li>{@see #ASPSESSIONIDQSADRCCB} is the cookie generated by the WMS server</li>
37 * </ul>
38 *
39 * You can still try to retrieve these session IDs invoking the servlet with
40 *
41 * <pre>
42 * http://.....?action=show-session-id
43 * </pre>
44 *
45 * but unfortunately the map server doesn't accept these cookies in subsequent
46 * orthofoto tile requests. You therefore have to get a valid session id with
47 * your favorite browser and enter it in the servlet using the servlets web form
48 * - see README.txt for more information.
49 *
50 * <strong>Actions</strong>
51 * <dl>
52 * <dt>http://....?action=ping</dt>
53 * <dd>Checks whether the servlet is alive (not the WMS server) and replies an
54 * OK text</dd>
55 *
56 * <dt>http://....?action=show-session-id</dt>
57 * <dd>Retrieves the session ids from the WMS server and displays them</dd>
58 *
59 * <dt>http://....?action=set-session-id[&session-id=thesessionid]</dt>
60 * <dd>Displays a form for entering the session id to be used in tile requests.</dd>
61 *
62 * <dt>http://....?action=get-map&</dt>
63 * <dd>Displays a form for entering the session id to be used in tile requests.
64 * Use <code>width</code>, <code>height</code>, and <code>bbox</code> as
65 * parameters. Replies the orthofoto tile from the web server of the city of
66 * Bern.</dd>
67 * <dl>
68 *
69 */
70public class OrthofotoBernWMSAdapter extends HttpServlet {
71
72 static public final String USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5";
73
74 /** the name of the session cookie used by www.stadtplan.bern.ch */
75 static public final String COOKIE_NAME_SESSION_ID1 = "ASPSESSIONIDQSADRCCB";
76 /**
77 * the name of the session cookie used by the WMS server of
78 * www.stadtplan.bern.ch
79 */
80 static public final String COOKIE_NAME_SESSION_ID2 = "ASP.NET_SessionId";
81
82 static public final String DEFAULT_URL_GEN_SESSION_ID1 = "http://www.stadtplan.bern.ch/";
83 static public final String DEFAULT_URL_GEN_SESSION_ID2 = "http://www.stadtplan.bern.ch/TBInternet/WebMapPageLV.aspx";
84
85 /** the logger */
86 private static Logger logger = Logger.getLogger(OrthofotoBernWMSAdapter.class.getName());
87
88 HashMap<String, String> cityMapSessionCookies = new HashMap<String, String>();
89
90 static private final String DEFAULT_LAYER = "TBI_orthofoto_08.mwf";
91 private String layer = DEFAULT_LAYER;
92
93 /**
94 * remembers session cookie retrieved from Berns map server
95 *
96 * @param headerField
97 * the header field with the session cookie
98 *
99 */
100 protected void rememberSessionCookie(String headerField) {
101 String cookie = headerField;
102 cookie = cookie.substring(0, cookie.indexOf(";"));
103 String cookieName = cookie.substring(0, cookie.indexOf("="));
104 String cookieValue = cookie.substring(cookie.indexOf("=") + 1, cookie
105 .length());
106 cityMapSessionCookies.put(cookieName, cookieValue);
107 if (!(cookieName.equals(COOKIE_NAME_SESSION_ID1) || cookieName
108 .equals(COOKIE_NAME_SESSION_ID2))) {
109 logger.warning("unexpected name for session cookie. name="
110 + cookieName + ",value=" + cookieValue);
111 }
112 }
113
114 /**
115 * retrieves the main session ID from Berns map application
116 *
117 * @exception IOException
118 * thrown, if an IO exception occurs
119 */
120 protected void getCityMapSessionID1() throws IOException {
121 URL url = null;
122
123 try {
124 url = new URL(DEFAULT_URL_GEN_SESSION_ID1);
125 } catch (MalformedURLException e) {
126 // should not happen, but log it anyway
127 logger.log(Level.SEVERE, e.toString());
128 return;
129 }
130
131 cityMapSessionCookies.remove(COOKIE_NAME_SESSION_ID1);
132
133 try {
134 URLConnection con = url.openConnection();
135 con.setRequestProperty("User-Agent", USER_AGENT);
136 con.connect();
137 String headerName = null;
138 for (int i = 1; (headerName = con.getHeaderFieldKey(i)) != null; i++) {
139 logger.log(Level.INFO, headerName + "="
140 + con.getHeaderField(headerName));
141 if (headerName.equals("Set-Cookie")) {
142 String cookie = con.getHeaderField(i);
143 rememberSessionCookie(cookie);
144 }
145 }
146 if (cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID1) == null) {
147 logger.log(Level.WARNING, "response did not include cookie "
148 + COOKIE_NAME_SESSION_ID1
149 + ". Further requests to the WMS server will timeout.");
150 } else {
151 logger.info("successfully retrieved cookie "
152 + COOKIE_NAME_SESSION_ID1 + ". value is <"
153 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID1)
154 + ">");
155 }
156 } catch (IOException e) {
157 logger.log(Level.SEVERE,
158 "failed to retrieve Session from Stadtplan Bern. "
159 + e.toString());
160 throw e;
161 }
162 }
163
164 /**
165 * retrieves the session ID from Berns WMS server. It mimics the behaviour
166 * of a standard browser as closely as possible. The request header fields
167 * sent to the remote server are those Firefox sends. They include a valid
168 * session ID from www.stadtplan.bern.ch.
169 *
170 * @exception IOException
171 * thrown, if an IO exception occurs
172 */
173
174 protected void getCityMapSessionID2() throws IOException {
175 URL url = null;
176
177 try {
178 url = new URL(DEFAULT_URL_GEN_SESSION_ID2);
179 } catch (MalformedURLException e) {
180 // should not happen, but log it anyway
181 logger.log(Level.SEVERE, e.toString());
182 return;
183 }
184
185 cityMapSessionCookies.remove(COOKIE_NAME_SESSION_ID2);
186
187 try {
188 URLConnection con = url.openConnection();
189 con.setRequestProperty("Host", "www.stadtplan.bern.ch");
190 con.setRequestProperty("Referer", "http://www.stadtplan.bern.ch/");
191 con.setRequestProperty("Cookie", COOKIE_NAME_SESSION_ID1 + "="
192 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID1));
193 con.setRequestProperty("User-Agent", USER_AGENT);
194 con
195 .setRequestProperty("Accept",
196 "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
197 con.setRequestProperty("Accept-Language",
198 "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3");
199 con.setRequestProperty("Accept-Encoding", "gzip,deflate");
200 con.setRequestProperty("Accept-Charset",
201 "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
202
203 con.connect();
204 String headerName = null;
205 for (int i = 1; (headerName = con.getHeaderFieldKey(i)) != null; i++) {
206 logger.log(Level.INFO, headerName + "="
207 + con.getHeaderField(headerName));
208 if (headerName.equals("Set-Cookie")) {
209 String cookie = con.getHeaderField(i);
210 rememberSessionCookie(cookie);
211 }
212 }
213 if (cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID2) == null) {
214 logger.log(Level.WARNING, "response did not include cookie "
215 + COOKIE_NAME_SESSION_ID2
216 + ". Further requests to the WMS server will timeout.");
217 } else {
218 logger.info("successfully retrieved cookie "
219 + COOKIE_NAME_SESSION_ID2 + ". value is <"
220 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID2)
221 + ">");
222 }
223
224 } catch (IOException e) {
225 logger.log(Level.SEVERE,
226 "failed to retrieve Session from Stadtplan Bern. "
227 + e.toString());
228 throw e;
229 }
230 }
231
232 /**
233 * retrieves a session id from the map application provided by the city of
234 * bern
235 *
236 * @throws IOException
237 * thrown, if the connection to the map application fails
238 */
239 protected void getCityMapSessionIDs() throws IOException {
240 getCityMapSessionID1();
241 getCityMapSessionID2();
242 }
243
244 /**
245 * true, if both the session IDs are known; false, otherwise
246 *
247 * @return true, if both the session IDs are known; false, otherwise
248 */
249 protected boolean hasCityMapSessionIDs() {
250 return cityMapSessionCookies != null
251 && cityMapSessionCookies.containsKey(COOKIE_NAME_SESSION_ID1)
252 && cityMapSessionCookies.containsKey(COOKIE_NAME_SESSION_ID2);
253 }
254
255 /**
256 * handles simple ping request
257 *
258 * @param request
259 * the http request
260 * @param response
261 * the http response
262 * @throws IOException
263 */
264 protected void handlePing(HttpServletRequest request,
265 HttpServletResponse response) throws IOException {
266 response.setStatus(HttpServletResponse.SC_OK);
267 PrintWriter pw = new PrintWriter(response.getWriter());
268 pw.println("OK");
269
270 }
271
272 /**
273 * handles a request for the current session ID
274 *
275 * @param req
276 * @param resp
277 * @throws IOException
278 */
279 protected void handleShowSessionId(HttpServletRequest req,
280 HttpServletResponse resp) throws IOException {
281 if (!hasCityMapSessionIDs()) {
282 getCityMapSessionIDs();
283 }
284
285 resp.setStatus(HttpServletResponse.SC_OK);
286 resp.setContentType("text/html");
287 PrintWriter pw = new PrintWriter(resp.getWriter());
288
289 if (cityMapSessionCookies.containsKey(COOKIE_NAME_SESSION_ID1)) {
290 pw.println("OK: " + COOKIE_NAME_SESSION_ID1 + "="
291 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID1));
292 } else {
293 pw.println("FAIL: " + COOKIE_NAME_SESSION_ID1 + " missing.");
294 }
295 pw.println("</br>");
296 if (cityMapSessionCookies.containsKey(COOKIE_NAME_SESSION_ID2)) {
297 pw.println("OK: " + COOKIE_NAME_SESSION_ID2 + "="
298 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID2));
299 } else {
300 pw.println("FAIL: " + COOKIE_NAME_SESSION_ID2 + " missing.");
301 }
302
303 }
304
305 protected String buildDefaultUrlForMapRequests() {
306 StringBuffer sb = new StringBuffer();
307 sb.append("http://www.stadtplan.bern.ch/TBInternet/WebMapServer.aspx?");
308 sb.append("VERSION=1.0.0").append("&");
309 sb.append("REQUEST=GETMAP").append("&");
310 sb.append("TYPE=11").append("&");
311 sb.append("LAYERS=").append(layer).append("&");
312 sb.append("FORMAT=image/jpeg").append("&");
313 sb.append("EXCEPTIONS=image/jpeg");
314 return sb.toString();
315 }
316
317 /**
318 * handles a tile request
319 *
320 * @param req
321 * the request
322 * @param resp
323 * the response
324 *
325 * @throws IOException
326 * thrown, if an IO exception occurs
327 * @throws OrthofotoBernWMSAdapterException
328 * thrown, if an exception occurs
329 */
330 protected void handleTileRequest(HttpServletRequest req,
331 HttpServletResponse resp) throws IOException,
332 OrthofotoBernWMSAdapterException {
333 int width;
334 int height;
335
336 // check parameters
337 //
338 if (req.getParameter("width") == null) {
339 throw new MissingParameterException("width");
340 }
341 try {
342 width = Integer.parseInt(req.getParameter("width"));
343 } catch (NumberFormatException e) {
344 throw new IllegalParameterValueException("width",
345 "illegal int value", e);
346 }
347
348 if (req.getParameter("height") == null) {
349 throw new MissingParameterException("height");
350 }
351 try {
352 height = Integer.parseInt(req.getParameter("height"));
353 } catch (NumberFormatException e) {
354 throw new IllegalParameterValueException("height",
355 "illegal int value", e);
356 }
357
358 if (req.getParameter("bbox") == null) {
359 throw new MissingParameterException("bbox");
360 }
361 BoundingBox bbox = new BoundingBox();
362 try {
363 bbox.fromString(req.getParameter("bbox"));
364 } catch (Exception e) {
365 throw new IllegalParameterValueException("bbox",
366 "failed to parse value", e);
367 }
368
369 // translate bounding box
370 //
371 bbox = BoundingBox.convertWGS84toCH1903(bbox);
372
373 if (!cityMapSessionCookies.containsKey(COOKIE_NAME_SESSION_ID2)) {
374 throw new OrthofotoBernWMSAdapterException(
375 "required session IDs missing. Can't proceed with request.");
376 }
377
378 // build request URL
379 //
380 StringBuffer sb = new StringBuffer();
381 sb.append(buildDefaultUrlForMapRequests());
382 sb.append("&WIDTH=");
383 sb.append(width);
384 sb.append("&HEIGHT=");
385 sb.append(height);
386 sb.append("&");
387 sb.append(bbox.toString());
388
389 logger.info("requesting tile with URL <" + sb.toString() + ">");
390
391 URL url;
392 try {
393 url = new URL(sb.toString());
394 } catch (MalformedURLException e) {
395 // should not happen, but log it anyway
396 logger.log(Level.SEVERE, e.toString());
397 throw new OrthofotoBernWMSAdapterException("failed to build URL", e);
398 }
399
400 try {
401 HttpURLConnection con = (HttpURLConnection) url.openConnection();
402 String cookie = String.format("%s=%s", COOKIE_NAME_SESSION_ID2,
403 cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID2));
404 logger.info("setting cookie <" + cookie + ">");
405 con.setRequestProperty("Cookie", cookie);
406 con.setRequestProperty("User-Agent", USER_AGENT);
407 con.setRequestProperty("Host", "www.stadtplan.bern.ch");
408 con
409 .setRequestProperty("Referer",
410 "http://www.stadtplan.bern.ch/TBInternet/WebMapPageLV.aspx");
411 con.setRequestProperty("Accept",
412 "image/jpeg,image/*;q=0.8,*/*;q=0.5");
413 con.setRequestProperty("Accept-Language",
414 "de-de,de;q=0.8,en-us;q=0.5,en;q=0.3");
415 con.setRequestProperty("Accept-Encoding", "gzip,deflate");
416 con.setRequestProperty("Accept-Charset",
417 "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
418 con.connect();
419 resp.setContentType("image/jpeg");
420 InputStream in = con.getInputStream();
421 OutputStream out = resp.getOutputStream();
422 byte[] buf = new byte[1024];
423 int read = in.read(buf);
424 while (read > 0) {
425 out.write(buf, 0, read);
426 read = in.read(buf);
427 }
428 in.close();
429
430 } catch (Exception e) {
431 throw new OrthofotoBernWMSAdapterException(
432 "failed to fetch orthofoto tile from map server", e);
433 }
434 }
435
436 protected void errorIllegalAction(HttpServletRequest request,
437 HttpServletResponse response, String action) throws IOException {
438 response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED,
439 "unexpected value for parameter 'action'. Got " + action);
440 }
441
442 protected String buildConfigurationForm(HttpServletRequest req) {
443 StringBuffer sb = new StringBuffer();
444 sb.append("<html><head></head><body>").append("\n");
445 sb.append("<h1>WMS Adapter for Orthofotos of Bern</h1>").append("\n");
446 sb.append("Please open <a href=\"http://www.stadtplan.bern.ch/TBInternet/default.aspx?User=1\">the city map of Bern</a> in your browser.</br>").append("\n");
447 sb.append("Then lookup the cookie <strong>ASP.Net_SessionId</strong> for domain <strong>www.stadtplan.bern.ch</strong> in your browser and enter it in the form below.</br>").append("\n");
448 sb.append("<form action=\"").append(req.getRequestURL()).append("\">").append("\n");
449 sb.append("<input type=\"hidden\" name=\"action\" value=\"set-session-id\">").append("\n");
450 sb.append("Session ID: <input type=\"text\" name=\"session-id\" value=\"\"><br/>").append("\n");
451 sb.append("Select a layer:<br/>").append("\n");
452 String checked;
453 if (layer == null || layer.equals("TBI_orthofoto_08.mwf")) {
454 checked=" checked ";
455 } else {
456 checked = "";
457 }
458 sb.append("<input type=\"radio\" name=\"layer\" value=\"TBI_orthofoto_08.mwf\"").append(checked).append(">Luftbilder 2008 Stadt Bern<br>").append("\n");
459 if (layer != null && layer.equals("orthofoto_Regio_08.mwf")) {
460 checked=" checked ";
461 } else {
462 checked = "";
463 }
464 sb.append("<input type=\"radio\" name=\"layer\" value=\"orthofoto_Regio_08.mwf\"").append(checked).append(">Luftbilder 2008 Region Bern<br>").append("\n");
465 sb.append("<input type=\"submit\" value=\"Submit\">").append("\n");
466 sb.append("</form").append("\n");
467 sb.append("</body></html>").append("\n");
468 return sb.toString();
469
470 }
471 protected void renderSessionIDInputForm(HttpServletRequest req,
472 HttpServletResponse resp) throws IOException {
473 PrintWriter pw = new PrintWriter(resp.getWriter());
474 pw.println(buildConfigurationForm(req));
475 }
476
477 protected void handleSetSessionId(HttpServletRequest req,
478 HttpServletResponse resp) throws OrthofotoBernWMSAdapterException,
479 IOException {
480 if (req.getParameter("session-id") == null) {
481 throw new MissingParameterException("session-id");
482 }
483 if (req.getParameter("layer") != null) {
484 layer = req.getParameter("layer");
485 } else {
486 layer = DEFAULT_LAYER;
487 }
488
489 cityMapSessionCookies.put(COOKIE_NAME_SESSION_ID2, req
490 .getParameter("session-id"));
491 logger.info("set session id <"
492 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID2) + ">");
493
494 String msg = "<html><head></head><body>\n"
495 + "<h1>WMS Adapter for Orthofots of Bern</h1>"
496 + "Session ID &lt;"
497 + cityMapSessionCookies.get(COOKIE_NAME_SESSION_ID2)
498 + "&gt; successfully set. You may now start to request map tiles from JOSM.</br></br>"
499 + "<a href=\""
500 + req.getRequestURL()
501 + "?action=getmap&bbox=7.4441276,46.9539095,7.4458911,46.9556731&width=500&height=499\">Click here for an example</a>"
502 + "</body></html>";
503
504 PrintWriter pw = new PrintWriter(resp.getWriter());
505 pw.println(msg);
506
507 }
508
509 @Override
510 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
511 throws ServletException, IOException {
512
513 logger.info("handling request <" + req.getRequestURI() + ">");
514
515 String action = req.getParameter("action");
516 if (action == null && req.getParameter("bbox") != null) {
517 action = "getmap";
518 }
519 logger.info("action is <" + action + ">");
520 if ("ping".equals(action)) {
521 handlePing(req, resp);
522 } else if ("show-session-id".equals(action)) {
523 handleShowSessionId(req, resp);
524 } else if ("getmap".equals(action)) {
525 try {
526 handleTileRequest(req, resp);
527 } catch (Exception e) {
528 logger.log(Level.SEVERE,
529 "exception while handling tile request.", e);
530 }
531 } else if ("set-session-id".equals(action)) {
532 try {
533 handleSetSessionId(req, resp);
534 } catch (OrthofotoBernWMSAdapterException e) {
535 throw new ServletException(
536 "exception caught while handing setting session id", e);
537 }
538 } else {
539 renderSessionIDInputForm(req, resp);
540 }
541 }
542}
Note: See TracBrowser for help on using the repository browser.