/*
* Copyright (c) 2001-2007, Inversoft Inc., All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*/
package org.primeframework.mvc.control;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import freemarker.core.Environment;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.ObjectWrapper;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
/**
* This class is a proxy between FreeMarker and the Prime MVC controls.
*
* @author Brian Pontarelli
*/
public class FreeMarkerControlProxy implements TemplateDirectiveModel {
private final Control control;
private final ObjectWrapper objectWrapper;
public FreeMarkerControlProxy(Control control, ObjectWrapper objectWrapper) {
this.control = control;
this.objectWrapper = objectWrapper;
}
/**
* Chains to the {@link Control#renderStart(java.io.Writer, java.util.Map, java.util.Map)} method and the {@link
* Control#renderEnd(java.io.Writer)}
*
* @param env The FreeMarker environment.
* @param params The parameters passed to this control in the FTL file.
* @param loopVars Loop variables (not really used).
* @param body The body of the directive.
*/
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
throws IOException, TemplateException {
Map<String, String> dynamicAttributes = makeDynamicAttributes(params);
Map<String, Object> attributes = makeAttributes(params);
control.renderStart(env.getOut(), attributes, dynamicAttributes);
control.renderBody(env.getOut(), new FreeMarkerBodyProxy(body));
control.renderEnd(env.getOut());
}
/**
* Executes the FreeMarker directive body if it is not null. Sub-classes can overwrite this method to change the body
* handling.
*
* @param env The environment that can be used to get the writer. This default implementation uses this writer.
* @param body The body.
* @throws TemplateException If the body fails to render.
* @throws IOException If the render can't write to the writer.
*/
protected void executeBody(Environment env, TemplateDirectiveBody body) throws IOException, TemplateException {
if (body != null) {
body.render(env.getOut());
}
}
/**
* Makes the attributes from the parameters passed to the control by unwrapping the FreeMarker models.
*
* @param params The parameters passed to this control in the FTL file.
* @return The attributes.
* @throws freemarker.template.TemplateModelException If the unwrapping fails.
*/
protected Map<String, Object> makeAttributes(Map params) throws TemplateModelException {
Map<String, Object> attributes = new HashMap<>(params.size());
for (Object o : params.entrySet()) {
Map.Entry entry = (Map.Entry) o;
Object value = entry.getValue();
if (value != null) {
attributes.put((String) entry.getKey(), ((BeansWrapper) objectWrapper).unwrap((TemplateModel) value));
}
}
return attributes;
}
/**
* Creates the list of dynamic attributes from the given Map of parameters passed ot the control.
*
* @param params The parameters passed to this control in the FTL file.
* @return The dynamic attributes.
*/
@SuppressWarnings("unchecked")
protected Map<String, String> makeDynamicAttributes(Map params) {
Map<String, String> dynamicAttributes = new HashMap<>();
for (Iterator<String> i = params.keySet().iterator(); i.hasNext(); ) {
String key = i.next();
if (key.startsWith("_")) {
Object value = params.get(key);
dynamicAttributes.put(key.substring(1), value.toString());
i.remove();
}
}
return dynamicAttributes;
}
}