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 :

http://dive4elements.wald.intevation.org