/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.ext.freemarker;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.Encoding;
import org.restlet.ext.freemarker.internal.ResolverHashModel;
import org.restlet.routing.Filter;
import org.restlet.util.Resolver;
import freemarker.template.Configuration;
import freemarker.template.TemplateHashModel;
/**
* Filter response's entity and wrap it with a FreeMarker's template
* representation. By default, the template representation provides a data model
* based on the request and response objects. In order for the wrapping to
* happen, the representations must have the {@link Encoding#FREEMARKER}
* encoding set.<br>
* <br>
* Concurrency note: instances of this class or its subclasses can be invoked by
* several threads at the same time and therefore must be thread-safe. You
* should be especially careful when storing state in member variables.
*
* @author Thierry Boileau
*/
public class TemplateFilter extends Filter {
/** The FreeMarker configuration. */
private volatile Configuration configuration;
/** The template's data model. */
private volatile Object dataModel;
/**
* Constructor.
*/
public TemplateFilter() {
super();
this.configuration = new Configuration();
}
/**
* Constructor.
*
* @param context
* The context.
*/
public TemplateFilter(Context context) {
super(context);
this.configuration = new Configuration();
}
/**
* Constructor.
*
* @param context
* The context.
* @param next
* The next Restlet.
*/
public TemplateFilter(Context context, Restlet next) {
super(context, next);
this.configuration = new Configuration();
}
/**
* Constructor.
*
* @param context
* The context.
* @param next
* The next Restlet.
* @param dataModel
* The filter's data model.
*/
public TemplateFilter(Context context, Restlet next, Object dataModel) {
this(context, next);
this.dataModel = dataModel;
}
/**
* Constructor.
*
* @param context
* The context.
* @param next
* The next Restlet.
* @param dataModel
* The filter's data model.
*/
public TemplateFilter(Context context, Restlet next,
Resolver<Object> dataModel) {
this(context, next);
this.dataModel = dataModel;
}
@Override
protected void afterHandle(Request request, Response response) {
if (response.isEntityAvailable()
&& response.getEntity().getEncodings()
.contains(Encoding.FREEMARKER)) {
TemplateRepresentation representation = new TemplateRepresentation(
response.getEntity(), this.configuration, response
.getEntity().getMediaType());
representation.setDataModel(createDataModel(request, response));
response.setEntity(representation);
}
}
/**
* Creates the FreeMarker data model for a given call. By default, it will
* create a {@link TemplateHashModel} based on the result of
* {@link Resolver#createResolver(Request, Response)}. If the
* {@link #getDataModel()} method has a non null value, it will be used.
*
* @param request
* The handled request.
* @param response
* The handled response.
* @return The FreeMarker data model for the given call.
*/
protected Object createDataModel(Request request, Response response) {
Object result = null;
if (this.dataModel == null) {
result = new ResolverHashModel(Resolver.createResolver(request,
response));
} else {
result = this.dataModel;
}
return result;
}
/**
* Returns the FreeMarker configuration.
*
* @return The FreeMarker configuration.
*/
public Configuration getConfiguration() {
return this.configuration;
}
/**
* Returns the template data model common to all calls. If each call should
* have a specific model, you should set this property to null.
*
* @return The template data model common to all calls.
*/
public Object getDataModel() {
return dataModel;
}
/**
* Sets the FreeMarker configuration.
*
* @param config
* FreeMarker configuration.
*/
public void setConfiguration(Configuration config) {
this.configuration = config;
}
/**
* Sets the template data model common to all calls. If each call should
* have a specific model, you should set this property to null.
*
* @param dataModel
* The template data model common to all calls.
*/
public void setDataModel(Object dataModel) {
this.dataModel = dataModel;
}
}