Mercurial > dive4elements > river
comparison gwt-client/src/main/java/org/dive4elements/river/client/server/MapPrintServiceImpl.java @ 5838:5aa05a7a34b7
Rename modules to more fitting names.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 25 Apr 2013 15:23:37 +0200 |
parents | flys-client/src/main/java/org/dive4elements/river/client/server/MapPrintServiceImpl.java@821a02bbfb4e |
children | 172338b1407f |
comparison
equal
deleted
inserted
replaced
5837:d9901a08d0a6 | 5838:5aa05a7a34b7 |
---|---|
1 package org.dive4elements.river.client.server; | |
2 | |
3 import org.dive4elements.artifacts.common.ArtifactNamespaceContext; | |
4 import org.dive4elements.artifacts.common.utils.ClientProtocolUtils; | |
5 import org.dive4elements.artifacts.common.utils.JSON; | |
6 import org.dive4elements.artifacts.common.utils.StringUtils; | |
7 import org.dive4elements.artifacts.common.utils.XMLUtils; | |
8 import org.dive4elements.artifacts.httpclient.exceptions.ConnectionException; | |
9 import org.dive4elements.artifacts.httpclient.http.HttpClient; | |
10 import org.dive4elements.artifacts.httpclient.http.HttpClientImpl; | |
11 import org.dive4elements.artifacts.httpclient.http.response.DocumentResponseHandler; | |
12 import org.dive4elements.river.client.shared.MapUtils; | |
13 import org.dive4elements.river.client.shared.model.MapConfig; | |
14 | |
15 import java.io.IOException; | |
16 import java.io.InputStream; | |
17 import java.io.OutputStream; | |
18 import java.io.UnsupportedEncodingException; | |
19 import java.net.URLEncoder; | |
20 import java.util.ArrayList; | |
21 import java.util.Collections; | |
22 import java.util.Enumeration; | |
23 import java.util.HashMap; | |
24 import java.util.LinkedHashMap; | |
25 import java.util.List; | |
26 import java.util.Map; | |
27 | |
28 import javax.servlet.ServletException; | |
29 import javax.servlet.http.HttpServlet; | |
30 import javax.servlet.http.HttpServletRequest; | |
31 import javax.servlet.http.HttpServletResponse; | |
32 | |
33 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; | |
34 import org.apache.commons.httpclient.methods.GetMethod; | |
35 import org.apache.log4j.Logger; | |
36 import org.w3c.dom.Document; | |
37 import org.w3c.dom.Element; | |
38 import org.w3c.dom.NodeList; | |
39 /* | |
40 import java.io.BufferedInputStream; | |
41 import java.io.BufferedOutputStream; | |
42 import java.io.File; | |
43 import java.io.FileInputStream; | |
44 import java.io.FileOutputStream; | |
45 */ | |
46 /* Used by direct API call. -> Enforce GPLv3 | |
47 import org.mapfish.print.MapPrinter; | |
48 import org.mapfish.print.output.OutputFactory; | |
49 import org.mapfish.print.output.OutputFormat; | |
50 | |
51 import org.mapfish.print.utils.PJsonObject; | |
52 */ | |
53 | |
54 public class MapPrintServiceImpl | |
55 extends HttpServlet | |
56 { | |
57 private static final Logger log = | |
58 Logger.getLogger(MapPrintServiceImpl.class); | |
59 | |
60 protected static class Layer implements Comparable<Layer> { | |
61 | |
62 protected int pos; | |
63 protected String url; | |
64 protected String layers; | |
65 protected String description; | |
66 | |
67 public Layer() { | |
68 } | |
69 | |
70 public boolean setup(Element element) { | |
71 | |
72 Element parent = (Element)element.getParentNode(); | |
73 String parentName = parent.getAttribute("name"); | |
74 if (!(parentName.equals("map") | |
75 || parentName.equals("floodmap"))) { | |
76 return false; | |
77 } | |
78 | |
79 String ns = ArtifactNamespaceContext.NAMESPACE_URI; | |
80 | |
81 String visible = element.getAttributeNS(ns, "visible"); | |
82 String active = element.getAttributeNS(ns, "active"); | |
83 | |
84 if (visible.equals("0") || active.equals("0")) { | |
85 return false; | |
86 } | |
87 | |
88 url = element.getAttributeNS(ns, "url"); | |
89 layers = element.getAttributeNS(ns, "layers"); | |
90 description = element.getAttributeNS(ns, "description"); | |
91 | |
92 try { | |
93 pos = Integer.parseInt(element.getAttributeNS(ns, "pos")); | |
94 } | |
95 catch (NumberFormatException nfe) { | |
96 return false; | |
97 } | |
98 | |
99 return true; | |
100 } | |
101 | |
102 public Map<String, Object> toMap() { | |
103 Map<String, Object> layer = new LinkedHashMap<String, Object>(); | |
104 | |
105 layer.put("type", "WMS"); | |
106 List<Object> subLayers = new ArrayList<Object>(1); | |
107 subLayers.add(layers); | |
108 layer.put("layers", subLayers); | |
109 // XXX: osm.intevation.de mapache only offers low dpi maps | |
110 // so we need to use the uncached service | |
111 layer.put("baseURL", url.replace("http://osm.intevation.de/mapcache/?", | |
112 "http://osm.intevation.de/cgi-bin/germany.fcgi?")); | |
113 layer.put("format", "image/png"); // TODO: Make configurable. | |
114 | |
115 return layer; | |
116 } | |
117 | |
118 @Override | |
119 public int compareTo(Layer other) { | |
120 int d = pos - other.pos; | |
121 if (d < 0) return -1; | |
122 return d > 0 ? +1 : 0; | |
123 } | |
124 } // class Layer | |
125 | |
126 protected static String generateSpec( | |
127 Document descDocument, | |
128 MapConfig mapConfig, | |
129 Double minX, Double minY, | |
130 Double maxX, Double maxY, | |
131 Map<String, Object> pageSpecs | |
132 ) { | |
133 Map<String, Object> spec = new LinkedHashMap<String, Object>(); | |
134 int dpi = 254; | |
135 spec.put("layout", "A4 landscape"); | |
136 spec.put("pageSize", "A4"); | |
137 spec.put("landscape", "true"); | |
138 spec.put("srs", "EPSG:" + mapConfig.getSrid()); | |
139 spec.put("dpi", dpi); | |
140 spec.put("units", "m"); | |
141 spec.put("geodaetic", "true"); | |
142 spec.put("outputFormat", "pdf"); | |
143 | |
144 spec.putAll(pageSpecs); | |
145 | |
146 String ns = ArtifactNamespaceContext.NAMESPACE_URI; | |
147 | |
148 List<Layer> ls = new ArrayList<Layer>(); | |
149 Layer l = new Layer(); | |
150 | |
151 NodeList facets = descDocument.getElementsByTagNameNS(ns, "facet"); | |
152 | |
153 for (int i = 0, N = facets.getLength(); i < N; ++i) { | |
154 Element element = (Element)facets.item(i); | |
155 if (l.setup(element)) { | |
156 ls.add(l); | |
157 l = new Layer(); | |
158 } | |
159 } | |
160 | |
161 // Establish Z order. | |
162 Collections.sort(ls); | |
163 | |
164 List<Object> layers = new ArrayList<Object>(ls.size()); | |
165 | |
166 for (int i = ls.size()-1; i >= 0; --i) { | |
167 layers.add(ls.get(i).toMap()); | |
168 } | |
169 | |
170 spec.put("layers", layers); | |
171 spec.put("name", "Name"); | |
172 | |
173 List<Object> pages = new ArrayList<Object>(1); | |
174 | |
175 | |
176 Map<String, Object> page = new LinkedHashMap<String, Object>(); | |
177 | |
178 List<Object> bounds = new ArrayList<Object>(4); | |
179 bounds.add(minX); | |
180 bounds.add(minY); | |
181 bounds.add(maxX); | |
182 bounds.add(maxY); | |
183 page.put("bbox", bounds); | |
184 | |
185 /* | |
186 bounds.add(Double.valueOf((minX+maxX)*0.5)); | |
187 bounds.add(Double.valueOf((minY+maxY)*0.5)); | |
188 | |
189 page.put("center", bounds); | |
190 page.put("scale", Integer.valueOf(50000)); | |
191 */ | |
192 | |
193 page.put("rotation", Integer.valueOf(0)); | |
194 | |
195 // This may overwrite default settings above | |
196 page.putAll(pageSpecs); | |
197 | |
198 pages.add(page); | |
199 spec.put("pages", pages); | |
200 | |
201 List<Object> legends = new ArrayList<Object>(layers.size()); | |
202 | |
203 for (Layer layer: ls) { | |
204 Map<String, Object> legend = new LinkedHashMap<String, Object>(); | |
205 List<Object> classes = new ArrayList<Object>(1); | |
206 Map<String, Object> clazz = new LinkedHashMap<String, Object>(); | |
207 String lgu = MapUtils.getLegendGraphicUrl(layer.url, layer.layers, dpi); | |
208 clazz.put("icon", lgu); | |
209 clazz.put("name", layer.description); | |
210 classes.add(clazz); | |
211 legend.put("classes", classes); | |
212 legend.put("name", layer.description); | |
213 legends.add(legend); | |
214 } | |
215 | |
216 spec.put("legends", legends); | |
217 | |
218 return JSON.toJSONString(spec); | |
219 } | |
220 | |
221 | |
222 @Override | |
223 public void doGet(HttpServletRequest req, HttpServletResponse resp) | |
224 throws ServletException, IOException | |
225 { | |
226 log.info("MapPrintServiceImpl.doGet"); | |
227 | |
228 String uuid = req.getParameter("uuid"); | |
229 | |
230 if (uuid == null || !StringUtils.checkUUID(uuid)) { | |
231 throw new ServletException("Missing or misspelled UUID"); | |
232 } | |
233 | |
234 String minXS = req.getParameter("minx"); | |
235 String maxXS = req.getParameter("maxx"); | |
236 String minYS = req.getParameter("miny"); | |
237 String maxYS = req.getParameter("maxy"); | |
238 | |
239 Double minX = null; | |
240 Double maxX = null; | |
241 Double minY = null; | |
242 Double maxY = null; | |
243 | |
244 if (minXS != null && maxXS != null | |
245 && minYS != null && maxYS != null) { | |
246 log.debug("all parameters found -> parsing"); | |
247 try { | |
248 minX = Double.parseDouble(minXS); | |
249 minY = Double.parseDouble(minYS); | |
250 maxX = Double.parseDouble(maxXS); | |
251 maxY = Double.parseDouble(maxYS); | |
252 } | |
253 catch (NumberFormatException nfe) { | |
254 throw new ServletException("Misspelled minX, minY, maxX or maxY"); | |
255 } | |
256 } | |
257 | |
258 String mapType = req.getParameter("maptype"); | |
259 | |
260 if (mapType == null || !mapType.equals("floodmap")) { | |
261 mapType = "map"; | |
262 } | |
263 | |
264 // Retrieve print settings from request | |
265 Map<String, Object> pageSpecs = new HashMap<String, Object>(); | |
266 Map<String, Object> data = new HashMap<String, Object>(); | |
267 List<Object> payload = new ArrayList<Object>(); | |
268 data.put("data", payload); | |
269 Enumeration paramNames = req.getParameterNames(); | |
270 List<String> params = Collections.list(paramNames); | |
271 Collections.sort(params); | |
272 for (String paramName : params) { | |
273 if (paramName.startsWith("mapfish_data_")) { | |
274 // You can add mapfish_data variables that will be mapped | |
275 // to a info value pairs to provide meta data for the map | |
276 // The the info part starts with a number for sorting that | |
277 // number will be stripped | |
278 String paramValue = req.getParameter(paramName); | |
279 Map<String, Object> data3 = new HashMap<String, Object>(); | |
280 int order = 0; | |
281 try { | |
282 order = Integer.parseInt(paramName.substring(13, 14)); | |
283 data3.put("info", paramName.substring(14)); | |
284 } catch (NumberFormatException nfe) { | |
285 data3.put("info", paramName.substring(13)); | |
286 payload.add(data3); | |
287 } | |
288 if (paramValue.equals("null")) | |
289 data3.put("value", ""); | |
290 else | |
291 data3.put("value", paramValue); | |
292 payload.add(data3); | |
293 } else if (paramName.startsWith("mapfish_")) { | |
294 String paramValue = req.getParameter(paramName); | |
295 if (paramValue.equals("null")) | |
296 paramValue = ""; | |
297 pageSpecs.put(paramName.substring(8), paramValue); | |
298 } | |
299 } | |
300 if (!payload.isEmpty()) { | |
301 pageSpecs.put("data", data); | |
302 List<Object> columns = new ArrayList<Object>(); | |
303 columns.add("info"); | |
304 columns.add("value"); | |
305 data.put("columns", columns); | |
306 } | |
307 | |
308 String url = getURL(); | |
309 | |
310 Document requestOut = | |
311 ClientProtocolUtils.newOutCollectionDocument( | |
312 uuid, mapType, mapType); | |
313 Document requestDesc = | |
314 ClientProtocolUtils.newDescribeCollectionDocument(uuid); | |
315 | |
316 Document outDocument; | |
317 Document descDocument; | |
318 | |
319 try { | |
320 HttpClient client = new HttpClientImpl(url); | |
321 | |
322 descDocument = (Document)client.doCollectionAction( | |
323 requestDesc, uuid, new DocumentResponseHandler()); | |
324 | |
325 InputStream is = client.collectionOut( | |
326 requestOut, uuid, mapType); | |
327 | |
328 try { | |
329 outDocument = XMLUtils.parseDocument(is); | |
330 } | |
331 finally { | |
332 is.close(); | |
333 is = null; | |
334 } | |
335 | |
336 } | |
337 catch (ConnectionException ce) { | |
338 log.error(ce); | |
339 throw new ServletException(ce); | |
340 } | |
341 | |
342 MapConfig mapConfig = MapHelper.parseConfig(outDocument); | |
343 | |
344 if (minX == null) { | |
345 log.debug("parameters missing -> fallback to max extent"); | |
346 String [] parts = mapConfig.getMaxExtent().split("\\s+"); | |
347 if (parts.length < 4) { | |
348 throw new ServletException( | |
349 "Max extent has less than 4 values"); | |
350 } | |
351 try { | |
352 minX = Double.valueOf(parts[0]); | |
353 minY = Double.valueOf(parts[1]); | |
354 maxX = Double.valueOf(parts[2]); | |
355 maxY = Double.valueOf(parts[3]); | |
356 } | |
357 catch (NumberFormatException nfe) { | |
358 throw new ServletException(nfe); | |
359 } | |
360 } | |
361 if (log.isDebugEnabled()) { | |
362 log.debug("minX: " + minX); | |
363 log.debug("maxX: " + maxX); | |
364 log.debug("minY: " + minY); | |
365 log.debug("maxY: " + maxY); | |
366 } | |
367 | |
368 String spec = generateSpec( | |
369 descDocument, | |
370 mapConfig, | |
371 minX, minY, | |
372 maxX, maxY, | |
373 pageSpecs); | |
374 | |
375 if (log.isDebugEnabled()) { | |
376 log.debug("Generated spec:"); | |
377 log.debug(spec); | |
378 //System.err.println(spec); | |
379 } | |
380 | |
381 producePDF(spec, resp); | |
382 } | |
383 | |
384 protected String getURL() throws ServletException { | |
385 String url = getServletContext().getInitParameter("server-url"); | |
386 if (url == null) { | |
387 throw new ServletException("Missing server-url"); | |
388 } | |
389 return url; | |
390 } | |
391 | |
392 private static final String encode(String s) { | |
393 try { | |
394 return URLEncoder.encode(s, "UTF-8"); | |
395 } | |
396 catch (UnsupportedEncodingException usee) { | |
397 // Should not happen. | |
398 return s; | |
399 } | |
400 } | |
401 | |
402 protected void producePDF(String json, HttpServletResponse resp) | |
403 throws ServletException, IOException | |
404 { | |
405 String printUrl = getInitParameter("print-url"); | |
406 | |
407 if (printUrl == null) { | |
408 throw new ServletException("Missing 'print-url' in web.xml"); | |
409 } | |
410 | |
411 String url = printUrl + "/print.pdf?spec=" + encode(json); | |
412 | |
413 org.apache.commons.httpclient.HttpClient client = | |
414 new org.apache.commons.httpclient.HttpClient( | |
415 new MultiThreadedHttpConnectionManager()); | |
416 | |
417 // FIXME: The request is not authenticated. | |
418 // Currently this is not a problem because /flys/map-print | |
419 // is whitelisted in GGInAFilter. | |
420 GetMethod get = new GetMethod(url); | |
421 int result = client.executeMethod(get); | |
422 InputStream in = get.getResponseBodyAsStream(); | |
423 | |
424 if (in != null) { | |
425 try { | |
426 OutputStream out = resp.getOutputStream(); | |
427 try { | |
428 byte [] buf = new byte[4096]; | |
429 int r; | |
430 if (result < 200 || result >= 300) { | |
431 resp.setContentType("text/plain"); | |
432 } else { | |
433 // Only send content disposition and filename content | |
434 // type when we have a pdf | |
435 resp.setHeader("Content-Disposition", | |
436 "attachment;filename=flys-karte.pdf"); | |
437 resp.setContentType("application/pdf"); | |
438 } | |
439 while ((r = in.read(buf)) >= 0) { | |
440 out.write(buf, 0, r); | |
441 } | |
442 out.flush(); | |
443 } | |
444 finally { | |
445 out.close(); | |
446 } | |
447 } | |
448 finally { | |
449 in.close(); | |
450 } | |
451 } | |
452 } | |
453 | |
454 /* Use this if you want directly call the MapPrinter. Enforces GPLv3! | |
455 | |
456 protected MapPrinter getMapPrinter() throws ServletException, IOException { | |
457 String configPath = getInitParameter("config"); | |
458 if (configPath == null) { | |
459 throw new ServletException("Missing configuration in web.xml"); | |
460 } | |
461 | |
462 File configFile = new File(configPath); | |
463 if (!configFile.isAbsolute()) { | |
464 configFile = new File(getServletContext().getRealPath(configPath)); | |
465 } | |
466 | |
467 if (!configFile.isFile() || !configFile.canRead()) { | |
468 throw new ServletException("Cannot read '" + configFile + "'"); | |
469 } | |
470 | |
471 return new MapPrinter(configFile); | |
472 } | |
473 | |
474 protected void producePDF(String json, HttpServletResponse resp) | |
475 throws ServletException, IOException | |
476 { | |
477 PJsonObject jsonSpec = MapPrinter.parseSpec(json); | |
478 | |
479 MapPrinter printer = getMapPrinter(); | |
480 | |
481 OutputFormat outputFormat = OutputFactory.create( | |
482 printer.getConfig(), jsonSpec); | |
483 | |
484 resp.setHeader("Content-Disposition", "attachment;filename=print.pdf"); | |
485 resp.setHeader("Content-Type", "application/pdf"); | |
486 | |
487 // XXX: Streaming the generated PDF directly | |
488 // to the request out does not work. :-/ | |
489 File tmpFile = File.createTempFile("map-printing", null); | |
490 | |
491 try { | |
492 OutputStream out = | |
493 new BufferedOutputStream( | |
494 new FileOutputStream(tmpFile)); | |
495 try { | |
496 outputFormat.print(printer, jsonSpec, out, ""); | |
497 out.flush(); | |
498 } | |
499 catch (Exception e) { | |
500 log.error(e); | |
501 throw new ServletException(e); | |
502 } | |
503 finally { | |
504 printer.stop(); | |
505 out.close(); | |
506 } | |
507 InputStream in = | |
508 new BufferedInputStream( | |
509 new FileInputStream(tmpFile)); | |
510 out = resp.getOutputStream(); | |
511 try { | |
512 byte [] buf = new byte[4096]; | |
513 int r; | |
514 while ((r = in.read(buf)) >= 0) { | |
515 out.write(buf, 0, r); | |
516 } | |
517 out.flush(); | |
518 } | |
519 finally { | |
520 in.close(); | |
521 out.close(); | |
522 } | |
523 } | |
524 finally { | |
525 if (tmpFile.exists()) { | |
526 tmpFile.delete(); | |
527 } | |
528 } | |
529 } | |
530 */ | |
531 } | |
532 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |