use of freemarker.template.TemplateModelException in project freemarker by apache.
the class NodeListModel method exec.
/**
* Applies an XPath expression to the node list and returns the resulting node list.
* In order for this method to work, your application must have access
* <a href="http://www.jaxen.org">Jaxen</a> library classes. The
* implementation does cache the parsed format of XPath expressions in a weak hash
* map, keyed by the string representation of the XPath expression. As the string
* object passed as the argument is usually kept in the parsed FreeMarker template,
* this ensures that each XPath expression is parsed only once during the lifetime
* of the FreeMarker template that contains it.
* @param arguments the list of arguments. Must contain exactly one string that is
* the XPath expression you wish to apply. The XPath expression can use any namespace
* prefixes that were defined using the {@link #registerNamespace(String, String)}
* method or the <code>nodelist._registerNamespace(prefix, uri)</code> expression in the
* template.
* @return a NodeListModel representing the nodes that are the result of application
* of the XPath to the current node list.
*/
public Object exec(List arguments) throws TemplateModelException {
if (arguments == null || arguments.size() != 1)
throw new TemplateModelException("Exactly one argument required for execute() on NodeTemplate");
String xpathString = (String) arguments.get(0);
JDOMXPathEx xpath = null;
try {
synchronized (XPATH_CACHE) {
xpath = (JDOMXPathEx) XPATH_CACHE.get(xpathString);
if (xpath == null) {
xpath = new JDOMXPathEx(xpathString);
XPATH_CACHE.put(xpathString, xpath);
}
}
return createNodeListModel(xpath.selectNodes(nodes, namespaces), namespaces);
} catch (Exception e) {
throw new TemplateModelException("Could not evaulate XPath expression " + xpathString, e);
}
}
use of freemarker.template.TemplateModelException in project freemarker by apache.
the class NodeListModel method get.
/**
* Provides node list traversal as well as special functions: filtering by name,
* filtering by node type, shallow-copying, and duplicate removal.
* While not as powerful as the full XPath support built into the
* {@link #exec(List)} method, it does not require the external Jaxen
* library to be present at run time. Below are listed the recognized keys.
* In key descriptions, "applicable to this-and-that node type" means that if
* a key is applied to a node list that contains a node of non-applicable type
* a TemplateMethodModel will be thrown. However, you can use <tt>_ftype</tt>
* key to explicitly filter out undesired node types prior to applying the
* restricted-applicability key. Also "current nodes" means nodes contained in this
* set.
* <ul>
* <li><tt>*</tt> or <tt>_children</tt>: all direct element children of current nodes (non-recursive). Applicable
* to element and document nodes.</li>
* <li><tt>@*</tt> or <tt>_attributes</tt>: all attributes of current nodes. Applicable to elements only.</li>
* <li><tt>_content</tt> the complete content of current nodes (non-recursive).
* Applicable to elements and documents.</li>
* <li><tt>_text</tt>: the text of current nodes, one string per node (non-recursive).
* Applicable to elements, attributes, comments, processing instructions (returns its data)
* and CDATA sections. The reserved XML characters ('<' and '&') are escaped.</li>
* <li><tt>_plaintext</tt>: same as <tt>_text</tt>, but does not escape any characters,
* and instead of returning a NodeList returns a SimpleScalar.</li>
* <li><tt>_name</tt>: the names of current nodes, one string per node (non-recursive).
* Applicable to elements and attributes (returns their local name),
* entities, processing instructions (returns its target), doctypes
* (returns its public ID)</li>
* <li><tt>_qname</tt>: the qualified names of current nodes in <tt>[namespacePrefix:]localName</tt>
* form, one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_cname</tt>: the canonical names of current nodes (namespace URI + local name),
* one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_nsprefix</tt>: namespace prefixes of current nodes,
* one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_nsuri</tt>: namespace URIs of current nodes,
* one string per node (non-recursive). Applicable to elements and attributes</li>
* <li><tt>_parent</tt>: parent elements of current nodes. Applicable to element, attribute, comment,
* entity, processing instruction.</li>
* <li><tt>_ancestor</tt>: all ancestors up to root element (recursive) of current nodes. Applicable
* to same node types as <tt>_parent</tt>.</li>
* <li><tt>_ancestorOrSelf</tt>: all ancestors of current nodes plus current nodes. Applicable
* to same node types as <tt>_parent</tt>.</li>
* <li><tt>_descendant</tt>: all recursive descendant element children of current nodes. Applicable to
* document and element nodes.
* <li><tt>_descendantOrSelf</tt>: all recursive descendant element children of current nodes
* plus current nodes. Applicable to document and element nodes.
* <li><tt>_document</tt>: all documents the current nodes belong to.
* Applicable to all nodes except text.
* <li><tt>_doctype</tt>: doctypes of the current nodes.
* Applicable to document nodes only.
* <li><tt>_fname</tt>: is a filter-by-name template method model. When called,
* it will yield a node list that contains only those current nodes whose name
* matches one of names passed as argument. Attribute names should NOT be prefixed with the
* at sign (@). Applicable on all node types, however has no effect on unnamed nodes.</li>
* <li><tt>_ftype</tt>: is a filter-by-type template method model. When called,
* it will yield a node list that contains only those current nodes whose type matches one
* of types passed as argument. You should pass a single string to this method
* containing the characters of all types to keep. Valid characters are:
* e (Element), a (Attribute), n (Entity), d (Document), t (DocType),
* c (Comment), p (ProcessingInstruction), x (text). If the string anywhere contains
* the exclamation mark (!), the filter's effect is inverted.</li>
* <li><tt>_type</tt>: Returns a one-character String SimpleScalar containing
* the typecode of the first node in the node list. Valid characters are:
* e (Element), a (Attribute), n (Entity), d (Document), t (DocType),
* c (Comment), p (ProcessingInstruction), x (text). If the type of the node
* is unknown, returns '?'. If the node list is empty, returns an empty string scalar.</li>
* <li><tt>_unique</tt>: a copy of the current nodes that keeps only the
* first occurrence of every node, eliminating duplicates. Duplicates can
* occur in the node list by applying uptree-traversals <tt>_parent</tt>,
* <tt>_ancestor</tt>, <tt>_ancestorOrSelf</tt>, and <tt>_document</tt>.
* I.e. <tt>foo._children._parent</tt> will return a node list that has
* duplicates of nodes in foo - each node will have the number of occurrences
* equal to the number of its children. In these cases, use
* <tt>foo._children._parent._unique</tt> to eliminate duplicates. Applicable
* to all node types.</li>
* <li><tt>_copy</tt>: a copy of the current node list. It is a shallow copy that
* shares the underlying node list with this node list, however it has a
* separate namespace registry, so it can be used to guarantee that subsequent
* changes to the set of registered namespaces does not affect the node lists
* that were used to create this node list. Applicable to all node types.</li>
* <li><tt>_registerNamespace(prefix, uri)</tt>: register a XML namespace
* with the specified prefix and URI for the current node list and all node
* lists that are derived from the current node list. After registering,
* you can use the <tt>nodelist["prefix:localname"]</tt> or
* <tt>nodelist["@prefix:localname"]</tt> syntaxes to reach elements and
* attributes whose names are namespace-scoped. Note that the namespace
* prefix need not match the actual prefix used by the XML document itself
* since namespaces are compared solely by their URI. You can also register
* namespaces from Java code using the
* {@link #registerNamespace(String, String)} method.
* </li>
* <li><tt>@attributeName</tt>: named attributes of current nodes. Applicable to
* elements, doctypes and processing instructions. On doctypes it supports
* attributes <tt>publicId</tt>, <tt>systemId</tt> and <tt>elementName</tt>. On processing
* instructions, it supports attributes <tt>target</tt> and <tt>data</tt>, as
* well as any other attribute name specified in data as <tt>name="value"</tt> pair.
* The attribute nodes for doctype and processing instruction are synthetic, and
* as such have no parent. Note, however that <tt>@*</tt> does NOT operate on
* doctypes or processing instructions.</li>
* <li>any other key: element children of current nodes with name matching the key.
* This allows for convenience child traversal in <tt>book.chapter.title</tt> style syntax.
* Note that <tt>nodeset.childname</tt> is technically equivalent to
* <tt>nodeset._children._fname("childname")</tt>, but is both shorter to write
* and evaluates faster. Applicable to document and element nodes.</li>
* </ul>
* The order of nodes in the resulting set is the order of evaluation of the key
* on each node in this set from left to right. Evaluation of the key on a single
* node always yields the results in "natural" order (that of the document preorder
* traversal), even for uptree traversals. As a consequence, if this node list's nodes
* are listed in natural order, applying any of the keys will produce a node list that
* is also naturally ordered. As a special case, all node lists that are directly or
* indirectly generated from a single Document or Element node through repeated
* invocations of this method will be naturally ordered.
* @param key a key that identifies a required set of nodes
* @return a new NodeListModel that represents the requested set of nodes.
*/
public TemplateModel get(String key) throws TemplateModelException {
if (isEmpty())
return EMPTY;
if (key == null || key.length() == 0)
throw new TemplateModelException("Invalid key [" + key + "]");
NodeOperator op = null;
NamedNodeOperator nop = null;
String name = null;
switch(key.charAt(0)) {
case '@':
{
if (key.length() != 2 || key.charAt(1) != '*') {
// Generic attribute key
nop = NAMED_ATTRIBUTE_OP;
name = key.substring(1);
} else
// It is @*
op = ALL_ATTRIBUTES_OP;
break;
}
case '*':
{
if (key.length() == 1)
op = ALL_CHILDREN_OP;
else
// Explicitly disallow any other identifier starting with asterisk
throw new TemplateModelException("Invalid key [" + key + "]");
break;
}
case 'x':
case '_':
{
op = (NodeOperator) OPERATIONS.get(key);
if (op == null) {
// Some special operation?
Integer specop = (Integer) SPECIAL_OPERATIONS.get(key);
if (specop != null) {
switch(specop.intValue()) {
case SPECIAL_OPERATION_COPY:
{
synchronized (namespaces) {
return new NodeListModel(nodes, (Map) ((HashMap) namespaces).clone());
}
}
case SPECIAL_OPERATION_UNIQUE:
return new NodeListModel(removeDuplicates(nodes), namespaces);
case SPECIAL_OPERATION_FILTER_NAME:
return new NameFilter();
case SPECIAL_OPERATION_FILTER_TYPE:
return new TypeFilter();
case SPECIAL_OPERATION_QUERY_TYPE:
return getType();
case SPECIAL_OPERATION_REGISTER_NAMESPACE:
return new RegisterNamespace();
case SPECIAL_OPERATION_PLAINTEXT:
return getPlainText();
}
}
}
break;
}
}
if (op == null && nop == null) {
nop = NAMED_CHILDREN_OP;
name = key;
}
List list = null;
if (op != null)
list = evaluateElementOperation(op, nodes);
else {
String localName = name;
Namespace namespace = Namespace.NO_NAMESPACE;
int colon = name.indexOf(':');
if (colon != -1) {
localName = name.substring(colon + 1);
String nsPrefix = name.substring(0, colon);
synchronized (namespaces) {
namespace = (Namespace) namespaces.get(nsPrefix);
}
if (namespace == null) {
if (nsPrefix.equals("xml"))
namespace = Namespace.XML_NAMESPACE;
else
throw new TemplateModelException("Unregistered namespace prefix '" + nsPrefix + "'");
}
}
list = evaluateNamedElementOperation(nop, localName, namespace, nodes);
}
return createNodeListModel(list, namespaces);
}
use of freemarker.template.TemplateModelException in project freemarker by apache.
the class FreemarkerServlet method createTaglibFactory.
/**
* Called to create the {@link TaglibFactory} once per servlet context.
* The default implementation configures it based on the servlet-init parameters and various other environmental
* settings, so if you override this method, you should call super, then adjust the result.
*
* @since 2.3.22
*/
protected TaglibFactory createTaglibFactory(ObjectWrapper objectWrapper, ServletContext servletContext) throws TemplateModelException {
TaglibFactory taglibFactory = new TaglibFactory(servletContext);
taglibFactory.setObjectWrapper(objectWrapper);
{
List /*<MetaInfTldSource>*/
mergedMetaInfTldSources = new ArrayList();
if (metaInfTldSources != null) {
mergedMetaInfTldSources.addAll(metaInfTldSources);
}
String sysPropVal = SecurityUtilities.getSystemProperty(SYSTEM_PROPERTY_META_INF_TLD_SOURCES, null);
if (sysPropVal != null) {
try {
List metaInfTldSourcesSysProp = parseAsMetaInfTldLocations(sysPropVal);
if (metaInfTldSourcesSysProp != null) {
mergedMetaInfTldSources.addAll(metaInfTldSourcesSysProp);
}
} catch (ParseException e) {
throw new TemplateModelException("Failed to parse system property \"" + SYSTEM_PROPERTY_META_INF_TLD_SOURCES + "\"", e);
}
}
List /*<Pattern>*/
jettyTaglibJarPatterns = null;
try {
final String attrVal = (String) servletContext.getAttribute(ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS);
jettyTaglibJarPatterns = attrVal != null ? InitParamParser.parseCommaSeparatedPatterns(attrVal) : null;
} catch (Exception e) {
LOG.error("Failed to parse application context attribute \"" + ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS + "\" - it will be ignored", e);
}
if (jettyTaglibJarPatterns != null) {
for (Iterator /*<Pattern>*/
it = jettyTaglibJarPatterns.iterator(); it.hasNext(); ) {
Pattern pattern = (Pattern) it.next();
mergedMetaInfTldSources.add(new ClasspathMetaInfTldSource(pattern));
}
}
taglibFactory.setMetaInfTldSources(mergedMetaInfTldSources);
}
{
List /*<String>*/
mergedClassPathTlds = new ArrayList();
if (classpathTlds != null) {
mergedClassPathTlds.addAll(classpathTlds);
}
String sysPropVal = SecurityUtilities.getSystemProperty(SYSTEM_PROPERTY_CLASSPATH_TLDS, null);
if (sysPropVal != null) {
try {
List /*<String>*/
classpathTldsSysProp = InitParamParser.parseCommaSeparatedList(sysPropVal);
if (classpathTldsSysProp != null) {
mergedClassPathTlds.addAll(classpathTldsSysProp);
}
} catch (ParseException e) {
throw new TemplateModelException("Failed to parse system property \"" + SYSTEM_PROPERTY_CLASSPATH_TLDS + "\"", e);
}
}
taglibFactory.setClasspathTlds(mergedClassPathTlds);
}
return taglibFactory;
}
use of freemarker.template.TemplateModelException in project freemarker by apache.
the class NodeListModel method getUniqueText.
private String getUniqueText(NodeListModel model, String property) throws TemplateModelException {
String s1 = null;
Set s = null;
for (Iterator it = model.nodes.iterator(); it.hasNext(); ) {
String s2 = (String) it.next();
if (s2 != null) {
// No text yet, make this text the current text
if (s1 == null) {
s1 = s2;
} else // accumulating them for an error message
if (!s1.equals(s2)) {
if (s == null) {
s = new HashSet();
s.add(s1);
}
s.add(s2);
}
}
}
// If the set for the error messages is empty, return the retval
if (s == null) {
return s1;
}
// Else throw an exception signaling ambiguity
throw new TemplateModelException("Value for node " + property + " is ambiguos: " + s);
}
use of freemarker.template.TemplateModelException in project freemarker by apache.
the class JspTagModelBase method setupTag.
void setupTag(Object tag, Map args, ObjectWrapper wrapper) throws TemplateModelException, InvocationTargetException, IllegalAccessException {
if (args != null && !args.isEmpty()) {
ObjectWrapperAndUnwrapper unwrapper = wrapper instanceof ObjectWrapperAndUnwrapper ? (ObjectWrapperAndUnwrapper) wrapper : // [2.4] Throw exception in this case
BeansWrapper.getDefaultInstance();
final Object[] argArray = new Object[1];
for (Iterator iter = args.entrySet().iterator(); iter.hasNext(); ) {
final Map.Entry entry = (Map.Entry) iter.next();
final Object arg = unwrapper.unwrap((TemplateModel) entry.getValue());
argArray[0] = arg;
final Object paramName = entry.getKey();
Method setterMethod = (Method) propertySetters.get(paramName);
if (setterMethod == null) {
if (dynaSetter == null) {
throw new TemplateModelException("Unknown property " + StringUtil.jQuote(paramName.toString()) + " on instance of " + tagClass.getName());
} else {
dynaSetter.invoke(tag, null, paramName, argArray[0]);
}
} else {
if (arg instanceof BigDecimal) {
argArray[0] = BeansWrapper.coerceBigDecimal((BigDecimal) arg, setterMethod.getParameterTypes()[0]);
}
try {
setterMethod.invoke(tag, argArray);
} catch (Exception e) {
final Class setterType = setterMethod.getParameterTypes()[0];
final _ErrorDescriptionBuilder desc = new _ErrorDescriptionBuilder("Failed to set JSP tag parameter ", new _DelayedJQuote(paramName), " (declared type: ", new _DelayedShortClassName(setterType) + ", actual value's type: ", (argArray[0] != null ? (Object) new _DelayedShortClassName(argArray[0].getClass()) : "Null"), "). See cause exception for the more specific cause...");
if (e instanceof IllegalArgumentException && !(setterType.isAssignableFrom(String.class)) && argArray[0] != null && argArray[0] instanceof String) {
desc.tip("This problem is often caused by unnecessary parameter quotation. Paramters " + "aren't quoted in FTL, similarly as they aren't quoted in most languages. " + "For example, these parameter assignments are wrong: ", "<@my.tag p1=\"true\" p2=\"10\" p3=\"${someVariable}\" p4=\"${x+1}\" />", ". The correct form is: ", "<@my.tag p1=true p2=10 p3=someVariable p4=x+1 />", ". Only string literals are quoted (regardless of where they occur): ", "<@my.box style=\"info\" message=\"Hello ${name}!\" width=200 />", ".");
}
throw new _TemplateModelException(e, null, desc);
}
}
}
}
}
Aggregations