Mercurial > dive4elements > river
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/MapPrintServiceImpl.java Thu Apr 25 15:23:37 2013 +0200 @@ -0,0 +1,532 @@ +package org.dive4elements.river.client.server; + +import org.dive4elements.artifacts.common.ArtifactNamespaceContext; +import org.dive4elements.artifacts.common.utils.ClientProtocolUtils; +import org.dive4elements.artifacts.common.utils.JSON; +import org.dive4elements.artifacts.common.utils.StringUtils; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.artifacts.httpclient.exceptions.ConnectionException; +import org.dive4elements.artifacts.httpclient.http.HttpClient; +import org.dive4elements.artifacts.httpclient.http.HttpClientImpl; +import org.dive4elements.artifacts.httpclient.http.response.DocumentResponseHandler; +import org.dive4elements.river.client.shared.MapUtils; +import org.dive4elements.river.client.shared.model.MapConfig; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +/* +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +*/ +/* Used by direct API call. -> Enforce GPLv3 +import org.mapfish.print.MapPrinter; +import org.mapfish.print.output.OutputFactory; +import org.mapfish.print.output.OutputFormat; + +import org.mapfish.print.utils.PJsonObject; +*/ + +public class MapPrintServiceImpl +extends HttpServlet +{ + private static final Logger log = + Logger.getLogger(MapPrintServiceImpl.class); + + protected static class Layer implements Comparable<Layer> { + + protected int pos; + protected String url; + protected String layers; + protected String description; + + public Layer() { + } + + public boolean setup(Element element) { + + Element parent = (Element)element.getParentNode(); + String parentName = parent.getAttribute("name"); + if (!(parentName.equals("map") + || parentName.equals("floodmap"))) { + return false; + } + + String ns = ArtifactNamespaceContext.NAMESPACE_URI; + + String visible = element.getAttributeNS(ns, "visible"); + String active = element.getAttributeNS(ns, "active"); + + if (visible.equals("0") || active.equals("0")) { + return false; + } + + url = element.getAttributeNS(ns, "url"); + layers = element.getAttributeNS(ns, "layers"); + description = element.getAttributeNS(ns, "description"); + + try { + pos = Integer.parseInt(element.getAttributeNS(ns, "pos")); + } + catch (NumberFormatException nfe) { + return false; + } + + return true; + } + + public Map<String, Object> toMap() { + Map<String, Object> layer = new LinkedHashMap<String, Object>(); + + layer.put("type", "WMS"); + List<Object> subLayers = new ArrayList<Object>(1); + subLayers.add(layers); + layer.put("layers", subLayers); + // XXX: osm.intevation.de mapache only offers low dpi maps + // so we need to use the uncached service + layer.put("baseURL", url.replace("http://osm.intevation.de/mapcache/?", + "http://osm.intevation.de/cgi-bin/germany.fcgi?")); + layer.put("format", "image/png"); // TODO: Make configurable. + + return layer; + } + + @Override + public int compareTo(Layer other) { + int d = pos - other.pos; + if (d < 0) return -1; + return d > 0 ? +1 : 0; + } + } // class Layer + + protected static String generateSpec( + Document descDocument, + MapConfig mapConfig, + Double minX, Double minY, + Double maxX, Double maxY, + Map<String, Object> pageSpecs + ) { + Map<String, Object> spec = new LinkedHashMap<String, Object>(); + int dpi = 254; + spec.put("layout", "A4 landscape"); + spec.put("pageSize", "A4"); + spec.put("landscape", "true"); + spec.put("srs", "EPSG:" + mapConfig.getSrid()); + spec.put("dpi", dpi); + spec.put("units", "m"); + spec.put("geodaetic", "true"); + spec.put("outputFormat", "pdf"); + + spec.putAll(pageSpecs); + + String ns = ArtifactNamespaceContext.NAMESPACE_URI; + + List<Layer> ls = new ArrayList<Layer>(); + Layer l = new Layer(); + + NodeList facets = descDocument.getElementsByTagNameNS(ns, "facet"); + + for (int i = 0, N = facets.getLength(); i < N; ++i) { + Element element = (Element)facets.item(i); + if (l.setup(element)) { + ls.add(l); + l = new Layer(); + } + } + + // Establish Z order. + Collections.sort(ls); + + List<Object> layers = new ArrayList<Object>(ls.size()); + + for (int i = ls.size()-1; i >= 0; --i) { + layers.add(ls.get(i).toMap()); + } + + spec.put("layers", layers); + spec.put("name", "Name"); + + List<Object> pages = new ArrayList<Object>(1); + + + Map<String, Object> page = new LinkedHashMap<String, Object>(); + + List<Object> bounds = new ArrayList<Object>(4); + bounds.add(minX); + bounds.add(minY); + bounds.add(maxX); + bounds.add(maxY); + page.put("bbox", bounds); + + /* + bounds.add(Double.valueOf((minX+maxX)*0.5)); + bounds.add(Double.valueOf((minY+maxY)*0.5)); + + page.put("center", bounds); + page.put("scale", Integer.valueOf(50000)); + */ + + page.put("rotation", Integer.valueOf(0)); + + // This may overwrite default settings above + page.putAll(pageSpecs); + + pages.add(page); + spec.put("pages", pages); + + List<Object> legends = new ArrayList<Object>(layers.size()); + + for (Layer layer: ls) { + Map<String, Object> legend = new LinkedHashMap<String, Object>(); + List<Object> classes = new ArrayList<Object>(1); + Map<String, Object> clazz = new LinkedHashMap<String, Object>(); + String lgu = MapUtils.getLegendGraphicUrl(layer.url, layer.layers, dpi); + clazz.put("icon", lgu); + clazz.put("name", layer.description); + classes.add(clazz); + legend.put("classes", classes); + legend.put("name", layer.description); + legends.add(legend); + } + + spec.put("legends", legends); + + return JSON.toJSONString(spec); + } + + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + log.info("MapPrintServiceImpl.doGet"); + + String uuid = req.getParameter("uuid"); + + if (uuid == null || !StringUtils.checkUUID(uuid)) { + throw new ServletException("Missing or misspelled UUID"); + } + + String minXS = req.getParameter("minx"); + String maxXS = req.getParameter("maxx"); + String minYS = req.getParameter("miny"); + String maxYS = req.getParameter("maxy"); + + Double minX = null; + Double maxX = null; + Double minY = null; + Double maxY = null; + + if (minXS != null && maxXS != null + && minYS != null && maxYS != null) { + log.debug("all parameters found -> parsing"); + try { + minX = Double.parseDouble(minXS); + minY = Double.parseDouble(minYS); + maxX = Double.parseDouble(maxXS); + maxY = Double.parseDouble(maxYS); + } + catch (NumberFormatException nfe) { + throw new ServletException("Misspelled minX, minY, maxX or maxY"); + } + } + + String mapType = req.getParameter("maptype"); + + if (mapType == null || !mapType.equals("floodmap")) { + mapType = "map"; + } + + // Retrieve print settings from request + Map<String, Object> pageSpecs = new HashMap<String, Object>(); + Map<String, Object> data = new HashMap<String, Object>(); + List<Object> payload = new ArrayList<Object>(); + data.put("data", payload); + Enumeration paramNames = req.getParameterNames(); + List<String> params = Collections.list(paramNames); + Collections.sort(params); + for (String paramName : params) { + if (paramName.startsWith("mapfish_data_")) { + // You can add mapfish_data variables that will be mapped + // to a info value pairs to provide meta data for the map + // The the info part starts with a number for sorting that + // number will be stripped + String paramValue = req.getParameter(paramName); + Map<String, Object> data3 = new HashMap<String, Object>(); + int order = 0; + try { + order = Integer.parseInt(paramName.substring(13, 14)); + data3.put("info", paramName.substring(14)); + } catch (NumberFormatException nfe) { + data3.put("info", paramName.substring(13)); + payload.add(data3); + } + if (paramValue.equals("null")) + data3.put("value", ""); + else + data3.put("value", paramValue); + payload.add(data3); + } else if (paramName.startsWith("mapfish_")) { + String paramValue = req.getParameter(paramName); + if (paramValue.equals("null")) + paramValue = ""; + pageSpecs.put(paramName.substring(8), paramValue); + } + } + if (!payload.isEmpty()) { + pageSpecs.put("data", data); + List<Object> columns = new ArrayList<Object>(); + columns.add("info"); + columns.add("value"); + data.put("columns", columns); + } + + String url = getURL(); + + Document requestOut = + ClientProtocolUtils.newOutCollectionDocument( + uuid, mapType, mapType); + Document requestDesc = + ClientProtocolUtils.newDescribeCollectionDocument(uuid); + + Document outDocument; + Document descDocument; + + try { + HttpClient client = new HttpClientImpl(url); + + descDocument = (Document)client.doCollectionAction( + requestDesc, uuid, new DocumentResponseHandler()); + + InputStream is = client.collectionOut( + requestOut, uuid, mapType); + + try { + outDocument = XMLUtils.parseDocument(is); + } + finally { + is.close(); + is = null; + } + + } + catch (ConnectionException ce) { + log.error(ce); + throw new ServletException(ce); + } + + MapConfig mapConfig = MapHelper.parseConfig(outDocument); + + if (minX == null) { + log.debug("parameters missing -> fallback to max extent"); + String [] parts = mapConfig.getMaxExtent().split("\\s+"); + if (parts.length < 4) { + throw new ServletException( + "Max extent has less than 4 values"); + } + try { + minX = Double.valueOf(parts[0]); + minY = Double.valueOf(parts[1]); + maxX = Double.valueOf(parts[2]); + maxY = Double.valueOf(parts[3]); + } + catch (NumberFormatException nfe) { + throw new ServletException(nfe); + } + } + if (log.isDebugEnabled()) { + log.debug("minX: " + minX); + log.debug("maxX: " + maxX); + log.debug("minY: " + minY); + log.debug("maxY: " + maxY); + } + + String spec = generateSpec( + descDocument, + mapConfig, + minX, minY, + maxX, maxY, + pageSpecs); + + if (log.isDebugEnabled()) { + log.debug("Generated spec:"); + log.debug(spec); + //System.err.println(spec); + } + + producePDF(spec, resp); + } + + protected String getURL() throws ServletException { + String url = getServletContext().getInitParameter("server-url"); + if (url == null) { + throw new ServletException("Missing server-url"); + } + return url; + } + + private static final String encode(String s) { + try { + return URLEncoder.encode(s, "UTF-8"); + } + catch (UnsupportedEncodingException usee) { + // Should not happen. + return s; + } + } + + protected void producePDF(String json, HttpServletResponse resp) + throws ServletException, IOException + { + String printUrl = getInitParameter("print-url"); + + if (printUrl == null) { + throw new ServletException("Missing 'print-url' in web.xml"); + } + + String url = printUrl + "/print.pdf?spec=" + encode(json); + + org.apache.commons.httpclient.HttpClient client = + new org.apache.commons.httpclient.HttpClient( + new MultiThreadedHttpConnectionManager()); + + // FIXME: The request is not authenticated. + // Currently this is not a problem because /flys/map-print + // is whitelisted in GGInAFilter. + GetMethod get = new GetMethod(url); + int result = client.executeMethod(get); + InputStream in = get.getResponseBodyAsStream(); + + if (in != null) { + try { + OutputStream out = resp.getOutputStream(); + try { + byte [] buf = new byte[4096]; + int r; + if (result < 200 || result >= 300) { + resp.setContentType("text/plain"); + } else { + // Only send content disposition and filename content + // type when we have a pdf + resp.setHeader("Content-Disposition", + "attachment;filename=flys-karte.pdf"); + resp.setContentType("application/pdf"); + } + while ((r = in.read(buf)) >= 0) { + out.write(buf, 0, r); + } + out.flush(); + } + finally { + out.close(); + } + } + finally { + in.close(); + } + } + } + + /* Use this if you want directly call the MapPrinter. Enforces GPLv3! + + protected MapPrinter getMapPrinter() throws ServletException, IOException { + String configPath = getInitParameter("config"); + if (configPath == null) { + throw new ServletException("Missing configuration in web.xml"); + } + + File configFile = new File(configPath); + if (!configFile.isAbsolute()) { + configFile = new File(getServletContext().getRealPath(configPath)); + } + + if (!configFile.isFile() || !configFile.canRead()) { + throw new ServletException("Cannot read '" + configFile + "'"); + } + + return new MapPrinter(configFile); + } + + protected void producePDF(String json, HttpServletResponse resp) + throws ServletException, IOException + { + PJsonObject jsonSpec = MapPrinter.parseSpec(json); + + MapPrinter printer = getMapPrinter(); + + OutputFormat outputFormat = OutputFactory.create( + printer.getConfig(), jsonSpec); + + resp.setHeader("Content-Disposition", "attachment;filename=print.pdf"); + resp.setHeader("Content-Type", "application/pdf"); + + // XXX: Streaming the generated PDF directly + // to the request out does not work. :-/ + File tmpFile = File.createTempFile("map-printing", null); + + try { + OutputStream out = + new BufferedOutputStream( + new FileOutputStream(tmpFile)); + try { + outputFormat.print(printer, jsonSpec, out, ""); + out.flush(); + } + catch (Exception e) { + log.error(e); + throw new ServletException(e); + } + finally { + printer.stop(); + out.close(); + } + InputStream in = + new BufferedInputStream( + new FileInputStream(tmpFile)); + out = resp.getOutputStream(); + try { + byte [] buf = new byte[4096]; + int r; + while ((r = in.read(buf)) >= 0) { + out.write(buf, 0, r); + } + out.flush(); + } + finally { + in.close(); + out.close(); + } + } + finally { + if (tmpFile.exists()) { + tmpFile.delete(); + } + } + } + */ +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :