/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.kml.decorator;
import java.util.Date;
import java.util.logging.Logger;
import org.geoserver.kml.KmlEncodingContext;
import org.geoserver.platform.ServiceException;
import org.geotools.util.Converter;
import org.geotools.util.Converters;
import org.geotools.util.logging.Logging;
import org.geotools.xml.XmlConverterFactory;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.AttributeType;
import org.opengis.feature.type.GeometryDescriptor;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.ExtendedData;
import de.micromata.opengis.kml.v_2_2_0.Feature;
import de.micromata.opengis.kml.v_2_2_0.Placemark;
import de.micromata.opengis.kml.v_2_2_0.Schema;
import de.micromata.opengis.kml.v_2_2_0.SchemaData;
import de.micromata.opengis.kml.v_2_2_0.SimpleData;
import de.micromata.opengis.kml.v_2_2_0.SimpleField;
/**
* Adds schema and attributes to the KML output
*
* @author Andrea Aime - GeoSolutions
*/
public class ExtendedDataDecoratorFactory implements KmlDecoratorFactory {
@Override
public KmlDecorator getDecorator(Class<? extends Feature> featureClass,
KmlEncodingContext context) {
if(!context.isExtendedDataEnabled()) {
return null;
}
if (Placemark.class.isAssignableFrom(featureClass)) {
return new PlacemarkDataDecorator();
} else if(Document.class.isAssignableFrom(featureClass)){
return new DocumentSchemaDecorator();
}
return null;
}
static class DocumentSchemaDecorator implements KmlDecorator {
@Override
public Feature decorate(Feature feature, KmlEncodingContext context) {
Document doc = (Document) feature;
// add a schema for each layer in the request (schemas have to be placed in the
// Document, can't be placed in a Folder unfortunately
int i = 1;
for (SimpleFeatureType schema : context.getFeatureTypes()) {
if(schema != null) {
String id = schema.getTypeName() + "_" + i;
addSchema(doc, id, schema);
}
i++;
}
return doc;
}
private void addSchema(Document doc, String id, SimpleFeatureType featureType) {
Schema schema = doc.createAndAddSchema();
schema.setId(id);
schema.setName(id);
for (AttributeDescriptor ad : featureType.getAttributeDescriptors()) {
// skip geometry attributes
if (ad instanceof GeometryDescriptor) {
continue;
}
SimpleField field = schema.createAndAddSimpleField();
field.setName(ad.getLocalName());
field.setType(getKmlFieldType(ad));
}
}
private String getKmlFieldType(AttributeDescriptor ad) {
AttributeType at = ad.getType();
if (Short.class.equals(at.getBinding())) {
return "short";
} else if (Integer.class.equals(at.getBinding())) {
return "int";
} else if (Float.class.equals(at.getBinding())) {
return "float";
} else if (Double.class.equals(at.getBinding())) {
return "double";
} else if (Boolean.class.equals(at.getBinding())) {
return "bool";
} else {
return "string";
}
}
}
static class PlacemarkDataDecorator implements KmlDecorator {
static final Logger LOGGER = Logging.getLogger(PlacemarkDataDecorator.class);
static final Converter DATE_CONVERTER = new XmlConverterFactory().createConverter(Date.class,
String.class, null);
@Override
public Feature decorate(Feature feature, KmlEncodingContext context) {
SimpleFeature sf = context.getCurrentFeature();
Placemark pm = (Placemark) feature;
// create the extended data, and encode any non null, non geometric attribute
ExtendedData exd = pm.createAndSetExtendedData();
SchemaData schemaData = exd.createAndAddSchemaData();
schemaData.setSchemaUrl("#" + context.getCurrentFeatureType().getTypeName() + "_" + context.getCurrentLayerIndex());
for (AttributeDescriptor ad : sf.getFeatureType().getAttributeDescriptors()) {
// skip geometry attributes
if (ad instanceof GeometryDescriptor) {
continue;
}
Object value = sf.getAttribute(ad.getLocalName());
if (value == null) {
continue;
}
// make an exception for dates
String kmlValue;
if (value instanceof Date) {
try {
kmlValue = DATE_CONVERTER.convert(value, String.class);
} catch (Exception e) {
throw new ServiceException("Failed to convert date into string while "
+ "generating extended data section", e);
}
} else {
kmlValue = Converters.convert(value, String.class);
}
SimpleData sd = schemaData.createAndAddSimpleData(ad.getLocalName());
sd.setValue(kmlValue);
}
return pm;
}
}
}