
org.jamon.compiler.TemplateInspector Maven / Gradle / Ivy
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.jamon.compiler;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jamon.AbstractTemplateProxy;
import org.jamon.TemplateManager;
import org.jamon.TemplateManagerSource;
import org.jamon.annotations.Argument;
import org.jamon.annotations.Template;
import org.jamon.util.StringUtils;
/**
* An TemplateInspector
manages the reflective rendering of a template, given a
* template path and a Map
of argument values as Strings. This class could certainly
* use some refactoring, and in fact, the public contract ought to allow reuse for multiple
* templates.
*/
public class TemplateInspector {
public static class InvalidTemplateException extends Exception {
public InvalidTemplateException(String p_templateName) {
this(p_templateName, null);
}
public InvalidTemplateException(String p_templateName, Throwable t) {
super(p_templateName + " does not appear to be a valid template class", t);
}
private static final long serialVersionUID = 2006091701L;
}
/**
* Construct an TemplateInspector
for a template path using the default
* {@link TemplateManager} as determined via the {@link TemplateManagerSource}.
*
* @param p_templateName the path of the template to be rendered
*/
public TemplateInspector(String p_templateName) throws InvalidTemplateException {
this(TemplateManagerSource.getTemplateManagerFor(p_templateName), p_templateName);
}
/**
* Construct an TemplateInspector
with a template manager, template path.
*
* @param p_manager the TemplateManager
to use
* @param p_templateName the path of the template to be rendered
*/
public TemplateInspector(TemplateManager manager, String templateName)
throws InvalidTemplateException {
template = manager.constructProxy(templateName);
templateClass = template.getClass();
Method[] methods = templateClass.getMethods();
Method renderMethod = null;
for (int i = 0; i < methods.length; ++i) {
if (methods[i].getName().equals("render")) {
renderMethod = methods[i];
break;
}
}
if (renderMethod == null) {
throw new InvalidTemplateException(templateName);
}
this.renderMethod = renderMethod;
Template templateAnnotation = templateClass.getAnnotation(Template.class);
requiredArgNames = getArgNames(templateAnnotation.requiredArguments());
optionalArgNames = getArgNames(templateAnnotation.optionalArguments());
}
private List getArgNames(Argument[] arguments) {
List argumentNames = new ArrayList(arguments.length);
for (Argument argument : arguments) {
argumentNames.add(argument.name());
}
return argumentNames;
}
/**
* Render the template.
*
* @param writer the Writer to render to
* @param argMap a Map<String,String> of arguments
*/
public void render(Writer writer, Map argMap) throws InvalidTemplateException,
UnknownArgumentsException {
render(writer, argMap, false);
}
/**
* Render the template.
*
* @param writer the Writer to render to
* @param argMap a Map<String,String> of arguments
* @param ignoreUnusedParams whether to throw an exception if "extra" arguments are supplied
*/
public void render(Writer writer, Map argMap, boolean ignoreUnusedParams)
throws InvalidTemplateException,
UnknownArgumentsException {
try {
if (!ignoreUnusedParams) {
validateArguments(argMap);
}
invokeOptionalArguments(argMap);
renderMethod.invoke(template, computeRenderArguments(argMap, writer));
}
catch (IllegalAccessException e) {
throw new InvalidTemplateException(templateClass.getName(), e);
}
catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof Error) {
throw (Error) t;
}
else if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
else {
throw new InvalidTemplateException(templateClass.getName(), t);
}
}
}
public List getRequiredArgumentNames() {
return requiredArgNames;
}
public List getOptionalArgumentNames() {
return optionalArgNames;
}
public Class> getArgumentType(String argName) {
if (optionalArgNames.contains(argName)) {
return findSetMethod(argName).getParameterTypes()[0];
}
else {
int i = requiredArgNames.indexOf(argName);
if (i < 0) {
return null;
}
else {
return renderMethod.getParameterTypes()[i + 1];
}
}
}
private Object[] computeRenderArguments(Map argMap, Writer writer) {
Object[] actuals = new Object[1 + requiredArgNames.size()];
actuals[0] = writer;
for (int i = 0; i < requiredArgNames.size(); ++i) {
actuals[i + 1] = argMap.get(requiredArgNames.get(i));
}
return actuals;
}
private void invokeOptionalArguments(Map argMap)
throws InvalidTemplateException {
for (int i = 0; i < optionalArgNames.size(); ++i) {
String name = optionalArgNames.get(i);
if (argMap.containsKey(name)) {
invokeSet(name, argMap.get(name));
}
}
}
public static class UnknownArgumentsException extends JamonException {
private static final long serialVersionUID = 2006091701L;
UnknownArgumentsException(String msg) {
super(msg);
}
}
private void validateArguments(Map argMap) throws UnknownArgumentsException {
Set argNames = new HashSet();
argNames.addAll(argMap.keySet());
argNames.removeAll(requiredArgNames);
argNames.removeAll(optionalArgNames);
if (!argNames.isEmpty()) {
StringBuilder msg = new StringBuilder("Unknown arguments supplied: ");
StringUtils.commaJoin(msg, argNames);
throw new UnknownArgumentsException(msg.toString());
}
}
private Method findSetMethod(String name) {
Method[] methods = templateClass.getMethods();
String upperName = "set" + Character.toUpperCase(name.charAt(0)) + name.substring(1);
for (int i = 0; i < methods.length; ++i) {
if (methods[i].getName().equals(upperName)) {
if (methods[i].getParameterTypes().length == 1) {
return methods[i];
}
}
}
return null;
}
private void invokeSet(String name, Object value) throws InvalidTemplateException {
Method setMethod = findSetMethod(name);
if (setMethod == null) {
throw new InvalidTemplateException(templateClass.getName() + " has no set method for "
+ name);
}
try {
setMethod.invoke(template, new Object[] { value });
}
catch (IllegalAccessException e) {
throw new InvalidTemplateException(templateClass.getName(), e);
}
catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
if (t instanceof Error) {
throw (Error) t;
}
else if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
else {
throw new InvalidTemplateException(templateClass.getName(), t);
}
}
}
private final Class> templateClass;
private final AbstractTemplateProxy template;
private final Method renderMethod;
private final List requiredArgNames;
private final List optionalArgNames;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy