org.geoserver.template.FeatureWrapper Maven / Gradle / Ivy
/* 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.template;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.geotools.feature.AttributeType;
import org.geotools.feature.Feature;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureType;
import org.geotools.feature.GeometryAttributeType;
import com.vividsolutions.jts.geom.Geometry;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.CollectionModel;
import freemarker.template.Configuration;
import freemarker.template.SimpleHash;
import freemarker.template.SimpleSequence;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
/**
* Wraps a {@link Feature} in the freemarker {@link BeansWrapper} interface
* allowing a template to be directly applied to a {@link Feature} or
* {@link FeatureCollection}.
*
* When a {@link FeatureCollection} is being processed by the template, it is
* available via the $features
variable, which can be broken down into single features and attributes following this hierarchy:
*
* - features -> feature
*
* - fid (String)
* - typeName (String)
* - attributes -> attribute
*
* - value (String), a default String representation of the attribute value
* - rawValue (Object), the actual attribute value if it's non null, the empty string otherwise
* - name (String)
* - type (String)
* - isGeometry (Boolean)
*
*
*
* Example of a template processing a feature collection which will print
* out the features id of every feature in the collection.
*
* <#list features as feature>
* FeatureId: ${feature.fid}
* </#list>
*
*
*
* To use this wrapper,use the {@link Configuration#setObjectWrapper(freemarker.template.ObjectWrapper)}
* method:
*
*
* //features we want to apply template to
* FeatureCollection features = ...;
*
* //create the configuration and set the wrapper
* Configuration cfg = new Configuration();
* cfg.setObjectWrapper( new FeatureWrapper() );
*
* //get the template and go
* Template template = cfg.getTemplate( "foo.ftl" );
* template.process( features, System.out );
*
*
*
*
*
* @author Justin Deoliveira, The Open Planning Project, [email protected]
* @author Andrea Aime, TOPP
*
*/
public class FeatureWrapper extends BeansWrapper {
public FeatureWrapper() {
setSimpleMapWrapper(true);
}
/**
* Returns a sensible String value for attributes so they are
* easily used by templates.
*
* Special cases:
*
* - for Date values returns a default {@link DateFormat} representation
* - for Boolean values returns "true" or "false"
* - for null values returns an empty string
* - for any other value returns its toString()
*
*
*
* @param o could be an instance of Date (a special case)
* @return the formated date as a String, or the object
*/
protected String wrapValue(Object o) {
if(o == null){
//nulls throw tempaltes off, use empty string
return "";
}
if ( o instanceof Date ) {
return DateFormat.getInstance().format( (Date)o );
}
if( o instanceof Boolean){
return ((Boolean)o).booleanValue()? "true" : "false";
}
return String.valueOf(o);
}
public TemplateModel wrap(Object object) throws TemplateModelException {
//check for feature collection
if (object instanceof FeatureCollection) {
//create a model with just one variable called 'features'
SimpleHash map = new SimpleHash();
map.put("features", new CollectionModel((FeatureCollection) object, this));
map.put("type", wrap(((FeatureCollection) object).getSchema()));
return map;
} else if (object instanceof FeatureType) {
FeatureType ft = (FeatureType) object;
// create a variable "attributes" which his a list of all the
// attributes, but at the same time, is a map keyed by name
Map attributeMap = new LinkedHashMap();
for (int i = 0; i < ft.getAttributeCount(); i++) {
AttributeType type = ft.getAttributeType(i);
Map attribute = new HashMap();
attribute.put("name", type.getLocalName());
attribute.put("type", type.getBinding().getName());
attribute.put("isGeometry", Boolean.valueOf(type instanceof GeometryAttributeType));
attributeMap.put(type.getLocalName(), attribute);
}
// build up the result, feature type is represented by its name an attributes
SimpleHash map = new SimpleHash();
map.put("attributes", new SequenceMapModel(attributeMap, this));
map.put("name", ft.getTypeName());
return map;
} else if (object instanceof Feature) {
Feature feature = (Feature) object;
//create the model
SimpleHash map = new SimpleHash();
//first add the feature id
map.put("fid", feature.getID());
map.put("typeName", feature.getFeatureType().getTypeName());
//next add variables for each attribute, variable name = name of attribute
SimpleSequence attributes = new SimpleSequence();
Map attributeMap = new LinkedHashMap();
for (int i = 0; i < feature.getNumberOfAttributes(); i++) {
AttributeType type = feature.getFeatureType().getAttributeType(i);
Map attribute = new HashMap();
Object value = feature.getAttribute(i);
attribute.put("value", wrapValue(value));
if ( value == null ) {
//some special case checks
attribute.put("rawValue", "");
attribute.put("isGeometry", Boolean.valueOf(Geometry.class.isAssignableFrom(type.getBinding())));
} else {
attribute.put("rawValue", value);
attribute.put("isGeometry", Boolean.valueOf(value instanceof Geometry));
}
attribute.put("name", type.getName());
attribute.put("type", type.getType().getName());
map.put(type.getName(), attribute);
attributeMap.put(type.getName(), attribute);
attributes.add(attribute);
}
// create a variable "attributes" which his a list of all the
// attributes, but at the same time, is a map keyed by name
map.put("attributes", new SequenceMapModel(attributeMap, this));
return map;
}
return super.wrap(object);
}
}