/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.geosearch.rest;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geoserver.config.GeoServerInfo;
import org.geoserver.kml.KMLLookAt;
import org.geoserver.kml.KMLNetworkLinkTransformer;
import org.geoserver.kml.KMLRasterTransformer;
import org.geoserver.kml.KMLTransformerBase;
import org.geoserver.kml.KMLUtils;
import org.geoserver.kml.KMLVectorTransformer;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.MapLayerInfo;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.map.Layer;
import org.geotools.map.Layer;
import org.geotools.renderer.lite.RendererUtilities;
import org.geotools.xml.transform.TransformerBase;
import org.geotools.xml.transform.Translator;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.AttributesImpl;
/**
* Transformer to create a KML document from a {@link WMSMapContent}.
* <p>
* The document is meant as a "metadata" document, and contains title and abstract taken from the
* {@link WMSMapContent#getTitle()} and {@link WMSMapContent#getAbstract()} respectively, and a
* networklink to the live kml contents.
*/
class KMLMetadataDocumentTransformer extends TransformerBase {
/**
* logger
*/
static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.kml");
private WMS wms;
public KMLMetadataDocumentTransformer(WMS wms) {
this.wms = wms;
setNamespaceDeclarationEnabled(false);
}
public Translator createTranslator(ContentHandler handler) {
return new KMLMetadataDocumentTranslator(handler);
}
/**
*
*
*/
protected class KMLMetadataDocumentTranslator extends TranslatorSupport {
/**
* Tolerance used to compare doubles for equality
*/
static final double TOLERANCE = 1e-6;
static final int RULES = 0;
static final int ELSE_RULES = 1;
private double scaleDenominator;
public KMLMetadataDocumentTranslator(ContentHandler handler) {
super(handler, null, null);
}
public void encode(Object o) throws IllegalArgumentException {
final WMSMapContent mapContent = (WMSMapContent) o;
final GetMapRequest request = mapContent.getRequest();
final List<Layer> layers = mapContent.layers();
final KMLLookAt lookAtOpts = new KMLLookAt(request.getFormatOptions());
// start("kml");
start("kml",
KMLUtils.attributes(new String[] { "xmlns", "http://www.opengis.net/kml/2.2",
"xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance", "xmlns:atom",
"http://www.w3.org/2005/Atom", "xsi:schemaLocation",
"http://www.opengis.net/kml/2.2 http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd" }));
// calculate scale denominator
scaleDenominator = 1;
try {
scaleDenominator = RendererUtilities.calculateScale(mapContent.getRenderingArea(),
mapContent.getMapWidth(), mapContent.getMapHeight(), null);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Error calculating scale denominator", e);
}
LOGGER.log(Level.FINE, "scale denominator = " + scaleDenominator);
start("Document");
String title = mapContent.getTitle();
element("name", title);
element("visibility", "1");
element("open", "1");
GeoServerInfo geoServerInfo = wms.getGeoServer().getGlobal();
element("atom:author", geoServerInfo.getContact().getContactPerson());
AttributesImpl href = new AttributesImpl();
href.addAttribute("", "href", "href", "", wms.getGeoServer().getGlobal()
.getOnlineResource());
element("atom:link", null, href);
String abstract1 = buildDescription(mapContent);
element("description", abstract1);
// encodeBbox(mapContent.getAreaOfInterest());
KMLNetworkLinkTransformer networkLinkTransformer = new KMLNetworkLinkTransformer(wms);
networkLinkTransformer.setStandalone(false);
networkLinkTransformer.setInline(true);
networkLinkTransformer.setIndentation(getIndentation());
networkLinkTransformer.setOmitXMLDeclaration(true);
networkLinkTransformer.setEncodeAsRegion(false);
// start("Folder");
// element("name", "Full Online Content");
networkLinkTransformer.createTranslator(contentHandler).encode(mapContent);
// end("Folder");
boolean includeSampleData = false;
for (int i = 0; i < layers.size(); i++) {
// layer and info
MapLayerInfo layerInfo = mapContent.getRequest().getLayers().get(i);
final int type = layerInfo.getType();
if (MapLayerInfo.TYPE_VECTOR == type || MapLayerInfo.TYPE_REMOTE_VECTOR == type) {
includeSampleData = true;
}
}
if (includeSampleData) {
// start("Folder");
// element("name", "Sample data");
// for every layer specified in the request
for (int i = 0; i < layers.size(); i++) {
// layer and info
Layer layer = layers.get(i);
MapLayerInfo layerInfo = mapContent.getRequest().getLayers().get(i);
// encodeSuperOverlayLayer(mapContent, layer);
if (layerInfo.getType() != MapLayerInfo.TYPE_RASTER) {
// vector
encodeVectorLayer(mapContent, layer, lookAtOpts);
} else {
// encode as normal ground overlay
encodeRasterLayer(mapContent, layer, lookAtOpts);
}
}
// end("Folder");
}
end("Document");
end("kml");
}
// private void encodeBbox(final ReferencedEnvelope latlonbbox) {
// start("LatLonBox");
// element("north", String.valueOf(latlonbbox.getMaxY()));
// element("south", String.valueOf(latlonbbox.getMinY()));
// element("east", String.valueOf(latlonbbox.getMaxX()));
// element("west", String.valueOf(latlonbbox.getMinX()));
// end("LatLonBox");
// }
private String buildDescription(WMSMapContent mapContent) {
StringBuilder sb = new StringBuilder();
if (null != mapContent.getAbstract()) {
sb.append(mapContent.getAbstract());
}
if (null != mapContent.getKeywords()) {
sb.append("\n");
for (String kw : mapContent.getKeywords()) {
if (null != kw) {
sb.append(kw).append(" ");
}
}
}
return sb.toString();
}
/**
* Encodes a vector layer as kml.
*/
protected void encodeVectorLayer(WMSMapContent mapContent, Layer layer,
KMLLookAt lookAtOpts) {
// get the data
SimpleFeatureSource featureSource = (SimpleFeatureSource) layer.getFeatureSource();
SimpleFeatureCollection features = null;
try {
features = KMLUtils.loadFeatureCollection(featureSource, layer, mapContent, wms,
scaleDenominator);
if (features == null) {
// it means no features need to be depicted with this style/scale denominator
return;
}
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
// kmz not selected, just do straight vector
KMLVectorTransformer tx = createVectorTransformer(mapContent, layer, lookAtOpts);
initTransformer(tx);
tx.setScaleDenominator(scaleDenominator);
Translator kmlTranslator = tx.createTranslator(contentHandler);
kmlTranslator.encode(features);
}
/**
* Factory method, allows subclasses to inject their own version of the raster transfomer
*
* @param mapContent
* @param lookAtOpts
* @return
*/
protected KMLRasterTransformer createRasterTransfomer(WMSMapContent mapContent,
KMLLookAt lookAtOpts) {
return new KMLRasterTransformer(wms, mapContent, lookAtOpts);
}
/**
* Factory method, allows subclasses to inject their own version of the vector transfomer
*
* @param mapContent
* @param lookAtOpts
* @return
*/
protected KMLVectorTransformer createVectorTransformer(WMSMapContent mapContent,
Layer layer, KMLLookAt lookAtOpts) {
return new KMLVectorTransformer(wms, mapContent, layer, lookAtOpts);
}
/**
* Encodes a raster layer as kml.
*/
protected void encodeRasterLayer(WMSMapContent mapContent, Layer layer,
KMLLookAt lookAtOpts) {
GetMapRequest request = mapContent.getRequest();
request.getFormatOptions().put("superoverlay", Boolean.TRUE);
KMLRasterTransformer tx = createRasterTransfomer(mapContent, lookAtOpts);
initTransformer(tx);
tx.createTranslator(contentHandler).encode(layer);
}
protected void initTransformer(KMLTransformerBase delegate) {
delegate.setIndentation(getIndentation());
delegate.setEncoding(getEncoding());
delegate.setStandAlone(false);
}
}
}