001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.vfny.geoserver.wms.responses.map.kml;
006:
007: import java.io.IOException;
008: import java.io.OutputStream;
009: import java.util.logging.Logger;
010: import java.util.zip.ZipEntry;
011: import java.util.zip.ZipOutputStream;
012:
013: import javax.xml.transform.TransformerException;
014:
015: import org.geotools.map.MapLayer;
016: import org.vfny.geoserver.ServiceException;
017: import org.vfny.geoserver.global.WMS;
018: import org.vfny.geoserver.wms.GetMapProducer;
019: import org.vfny.geoserver.wms.WMSMapContext;
020: import org.vfny.geoserver.wms.WmsException;
021: import org.vfny.geoserver.wms.responses.AbstractGetMapProducer;
022: import org.vfny.geoserver.wms.responses.map.png.PNGMapProducer;
023:
024: /**
025: * Handles a GetMap request that spects a map in KMZ format.
026: *
027: * KMZ files are a zipped KML file. The KML file must have an emcompasing
028: * <document> or <folder> element. So if you have many different placemarks or
029: * ground overlays, they all need to be contained within one <document> element,
030: * then zipped up and sent off with the extension "kmz".
031: *
032: * @author $Author: Alessio Fabiani (alessio.fabiani@gmail.com) $
033: * @author $Author: Simone Giannecchini (simboss1@gmail.com) $
034: * @author $Author: Brent Owens
035: * @author Justin Deoliveira
036: *
037: */
038: class KMZMapProducer extends AbstractGetMapProducer implements
039: GetMapProducer {
040: /** standard logger */
041: private static final Logger LOGGER = org.geotools.util.logging.Logging
042: .getLogger("org.vfny.geoserver.responses.wms.kmz");
043:
044: /**
045: * delegating producer for rendering.
046: */
047: PNGMapProducer mapProducer;
048:
049: /**
050: * transformer for creating kml
051: */
052: KMLTransformer transformer;
053:
054: public KMZMapProducer(String mapFormat, String mime_type, WMS wms) {
055: super (mapFormat, mime_type);
056: mapProducer = new PNGMapProducer("image/png", "image/png", wms);
057: }
058:
059: public void abort() {
060: LOGGER.fine("aborting KMZ map response");
061: mapContext = null;
062: mapProducer = null;
063: transformer = null;
064: }
065:
066: public String getContentDisposition() {
067: StringBuffer sb = new StringBuffer();
068: for (int i = 0; i < mapContext.getLayerCount(); i++) {
069: MapLayer layer = mapContext.getLayer(i);
070: String title = layer.getFeatureSource().getSchema()
071: .getTypeName();
072: if (title != null && !title.equals("")) {
073: sb.append(title).append("_");
074: }
075: }
076: if (sb.length() > 0) {
077: sb.setLength(sb.length() - 1);
078: return "attachment; filename=" + sb.toString() + ".kml";
079: }
080: return "attachment; filename=geoserver.kml";
081: }
082:
083: public String getContentType() throws IllegalStateException {
084: return KMZMapProducerFactory.MIME_TYPE;
085: }
086:
087: /**
088: * Initializes the KML encoder. None of the map production is done here, it
089: * is done in writeTo(). This way the output can be streamed directly to the
090: * output response and not written to disk first, then loaded in and then
091: * sent to the response.
092: *
093: * @param map
094: * WMSMapContext describing what layers, styles, area of interest
095: * etc are to be used when producing the map.
096: *
097: * @throws WmsException
098: * thrown if anything goes wrong during the production.
099: */
100: public void produceMap() throws WmsException {
101: transformer = new KMLTransformer();
102: transformer.setKmz(true);
103:
104: // TODO: use GeoServer.isVerbose() to determine if we should indent?
105: transformer.setIndentation(3);
106: }
107:
108: /**
109: * Makes the map and sends it to the zipped output stream The produceMap()
110: * method does not create the map in this case. We produce the map here so
111: * we can stream directly to the response output stream, and not have to
112: * write to disk, then send it to the stream.
113: *
114: * @Note: Do not close the output stream in this method, it gets closed
115: * later on.
116: *
117: * @param out
118: * OutputStream to stream the map to.
119: *
120: * @throws ServiceException
121: * @throws IOException
122: *
123: */
124: public void writeTo(OutputStream out) throws ServiceException,
125: IOException {
126: // wrap the output stream in a zipped one
127: ZipOutputStream zip = new ZipOutputStream(out);
128:
129: // first create an entry for the kml
130: ZipEntry entry = new ZipEntry("wms.kml");
131: zip.putNextEntry(entry);
132:
133: try {
134: transformer.transform(mapContext, zip);
135: zip.closeEntry();
136: } catch (TransformerException e) {
137: throw (IOException) new IOException().initCause(e);
138: }
139:
140: // write the images
141: for (int i = 0; i < mapContext.getLayerCount(); i++) {
142: MapLayer mapLayer = mapContext.getLayer(i);
143:
144: // create a context for this single layer
145: WMSMapContext mapContext = new WMSMapContext();
146: mapContext.addLayer(mapLayer);
147: mapContext.setRequest(this .mapContext.getRequest());
148: mapContext.setMapHeight(this .mapContext.getMapHeight());
149: mapContext.setMapWidth(this .mapContext.getMapWidth());
150: mapContext.setAreaOfInterest(this .mapContext
151: .getAreaOfInterest());
152: mapContext.setBgColor(this .mapContext.getBgColor());
153: mapContext.setBuffer(this .mapContext.getBuffer());
154: mapContext.setContactInformation(this .mapContext
155: .getContactInformation());
156: mapContext.setKeywords(this .mapContext.getKeywords());
157: mapContext.setAbstract(this .mapContext.getAbstract());
158: mapContext.setTransparent(true);
159:
160: // render the map
161: mapProducer.setMapContext(mapContext);
162: mapProducer.produceMap();
163:
164: // write it to the zip stream
165: entry = new ZipEntry("layer_" + i + ".png");
166: zip.putNextEntry(entry);
167: mapProducer.writeTo(zip);
168: zip.closeEntry();
169: }
170:
171: zip.finish();
172: zip.flush();
173: }
174: }
|