GeoServer : Templates
This page last changed on Mar 05, 2007 by bowens.
This page contains information about the design and implementation of a GeoServer templating system. Here we will nail down the requirements and features of such a system, as well as evaluate a number of the candidate technologies for implementation.
While the idea of using a template is somewhat of a developer concept, templates are something that end users will interfact with directly, some of which may have little or no programming knowledge. We want creating a new template to be as simple as possible.
Perhaps falling under "ease of use", users will need to be able to add new templates to GeoServer as easily as possible. Adding a new template should be as simple as creating it with a text editor, and saving it to particular location.
As with anything else, performance is always a key issue. At the end of the day the template system will be applied to large collections of features. The templating engine must be capable of processing these in an efficient, streaming manner.
Secondly, adding a templating engine between pulling our data off of disk and showing to the user is a level of indirection that could lead to a potential bottleneck. We want to make sure we choose an engine that performs well.
Often templating engines out of the box work great for normal java objects or POJO;s as they are commonly refered. However in our domain we are not so lucky as we work with Features. The structure of a feature is something that a templating engine will not know about out of the box, so it needs to be flexible enough and provide an API to allow us to "teach" it about features. The point of which is to allow the end template designer to be able to interfact with features as if they were interacting with a POJO.
An important initial question is "How will templates be used by GeoServer?". A couple of scenarios have already popped up on the mailing lists and in feature requests which are well suited to templates. In particular...
In KML placemarks contain a description element, which can contain HTML describing various things about the placemark. When GeoServer outputs KML a placemark is generated for every feature which matche3. d the original request. Currently GeoServer defaults to creating a simple HTML table containing all the attributes of the feature as shown below:
Users have asked for the ability to:
The possibilities are endless.
The WMS GetFeatureInfo operation defines the info_format parameter which specifies the format that should be used to relay the information about a set of features matching a particular criteria. GeoServer provides a couple of differnt formats out of the box such as plain text, and GML. One of interest is HTML, in which matching features are output in a simple table shown below:
The general workflow of any templating system is generally the same. A service has some data that has been requested, and needs to apply a template to it in order to present it.
The first step in using a template is loading it. Which begs the question "How will templates be loaded by GeoServer?". Since a template is just a file this really depends on how templates are stored. A logical place to store them is in the GeoServer data directory since it is where all configuration for GeoServer gets stored. We have a couple of options for this.
One possibility would be to create a new sub directory in the GeoServer data directory structure called "templates". This could be a single location for all templates to be stored.
More often then not, a template will be applied to a single feature collection or single feature. Which means the template is specific to a particular feature type. For his reason it would make sense to store the template in the appropriate directory under "featureTypes", since that is where all configuration specific to a single feature type ( eg. info.xml ), is located.
A case could be made for both of the above. Some times applying a template will be specific to a feature type, sometimes not. So why not both? Most template engines can be configured to load templates from any location, so it should be possible to configure multiple locations.
More often then not templates will be applied to features and feature collections. So the question becomes how do we want to expose our feature model to someone writing a template? In our feature model a feature can be represented as a row in a table. For sake of example lets consider the following feature collection:
Normally in a template, properties of an object are available via a simple variable syntax. Lets consider for a moment that our feature was modelled as a java bean:
In a template, we would be able to access properties like the following:
This is nice because it is a simple syntax and is something that is generally standard across most templating engines and syntaxes. So it would desirable to adopt this same syntax for our features.
While the above syntax is nice and simple, it may be a bit too simple for some users. For one it requires that the template writer know exactly what the attributes of the feature type are before hand. This may not be desirable. Perhaps some more dynamic or reflective access is required.
One solution would be to introduce a special variable called attributes, which could be a simple list of the attributes for the feature. Each attribute could contain a name,value pair. Access in a template would look something like:
There are a number of templating libraries at our disposal each with its own features and advantages. A extensive list can be found at http://java-source.net/open-source/template-engines. We will evaluate some of the more popular ones here. Please feel free to add additional information to this section in particular if you are familiar with a particular templating technology.
For each evaluation, we will try to answer the following questions.
Velocity is probably the most well-known of template engines.
The general recipe for invoking a velocity template is as follows:
More details here.
Configuring template locations is pretty easy with velocity. It provides a simple properties format for controlling how templates are loaded. For instance, setting templates to be loaded from a particular directory:
Getting a bit more advanced, overriding the template lookup mechanism is also pretty easy. Consider a custom template loader which can load templates dynamically from a GeoServer data directory by extending the velocity FileResourceLoader.
Pointing the engine at the custom template loader is achieved again with a property:
I found that Velocity was a bit lacking when it came to teaching it about non java bean based object models like the geotools feature. Setting properties in a "context" is somewhat tedious and uses a map-like api:
Access in a template then becomes:
There a couple of things to note about this approach:
For 1, there is some light at the end of the tunnel. Velocity does contain the FieldMethodizer class which it used to be able to provide access to fields of a class directly. A quick subclass hack can be used to adapt it to feature attributes.
Instances of this class can then wrap up features as they are thrown in the context:
For number 2, consider the situation of having a FeatureCollection and wanting to apply the template to the entire collection.
We lose the ability to set features in the context, which means that access in the template becomes more complicated.
On the one hand we lose our very simple access to features as things become much more verbose. On the other hand we provide the template writer with a lot of flexibility as they have full access to the feature api.
Freemarker is another popular java templating engine.
The general recipe for invoking a freemarker template is as follows:
More info here.
Similar to Velocity customizing template loading relatively straight forward. Loading a template from a particular location looks like:
And again, its also easy to create a custom template loading implementation:
Freemarker provides an interface called BeansWrapper for explicitly wrapping up non java bean objects. An implementation for wrapping up features could look like:
One of the really nice things about this implementation is that it handles both features and feature collections transparently. Using it in a template becomes:
KML has had the most requests to be "templatable": people want to limit or style the amount of information returned to the user for their placemarks.
The possible requirements for a user are:
In the SLD file, an example of how a template could be specified:
The template could be specified in a vendor option, or our own tag if we want to modify the SLD schema.
It should be noted that KML features will be rendered with a placemark whether or not a text symbolizer is defined.
In the template, it could look something like this:
|Document generated by Confluence on May 14, 2014 23:00|