libfreemarker-java-2.3.19.orig/0000755000175000017500000000000011723544475015642 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/LICENSE.txt0000644000175000017500000000713211723544470017463 0ustar ebourgebourgFreeMarker 1.x was released under the LGPL license. Later, by community consensus, we have switched over to a BSD-style license. As of FreeMarker 2.2pre1, the original author, Benjamin Geer, has relinquished the copyright in behalf of Visigoth Software Society. The current copyright holder is the Visigoth Software Society. ------------------------------------------------------------------------------ Copyright (c) 2003 The Visigoth Software Society. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The end-user documentation included with the redistribution, if any, must include the following acknowlegement: "This product includes software developed by the Visigoth Software Society (http://www.visigoths.org/)." Alternately, this acknowlegement may appear in the software itself, if and wherever such third-party acknowlegements normally appear. 3. Neither the name "FreeMarker", "Visigoth", nor any of the names of the project contributors may be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact visigoths@visigoths.org. 4. Products derived from this software may not be called "FreeMarker" or "Visigoth" nor may "FreeMarker" or "Visigoth" appear in their names without prior written permission of the Visigoth Software Society. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------ This software consists of voluntary contributions made by many individuals on behalf of the Visigoth Software Society. For more information on the Visigoth Software Society, please see http://www.visigoths.org/ ------------------------------------------------------------------------------ FREEMARKER SUBCOMPONENTS UNDER DIFFERENT LICENSE: FreeMarker includes a number of subcomponents that are licensed by the Apache Software Foundation under the Apache License, Version 2.0. Your use of these subcomponents is subject to the terms and conditions of the Apache License, Version 2.0. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 The subcomponents under this licence are the following files, which are included both in freemarker.jar and in the source code: freemarker/ext/jsp/web-app_2_2.dtd freemarker/ext/jsp/web-app_2_3.dtd freemarker/ext/jsp/web-app_2_4.xsd freemarker/ext/jsp/web-app_2_5.xsd freemarker/ext/jsp/web-jsptaglibrary_1_1.dtd freemarker/ext/jsp/web-jsptaglibrary_1_2.dtd freemarker/ext/jsp/web-jsptaglibrary_2_0.xsd freemarker/ext/jsp/web-jsptaglibrary_2_1.xsd libfreemarker-java-2.3.19.orig/lib/0000755000175000017500000000000012164627123016400 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/0000755000175000017500000000000011723544470016424 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/0000755000175000017500000000000012164627123020544 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/core/0000755000175000017500000000000012164627123021474 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/core/NewBI.java0000644000175000017500000001273611723544470023317 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.List; import freemarker.ext.beans.BeansWrapper; import freemarker.template.ObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateScalarModel; /** * A built-in that allows us to instantiate an instance of a java class. * Usage is something like: * <#assign foobar = "foo.bar.MyClass"?new() /> */ class NewBI extends BuiltIn { static final Class TM_CLASS = TemplateModel.class; static final Class BEAN_MODEL_CLASS = freemarker.ext.beans.BeanModel.class; static Class JYTHON_MODEL_CLASS; static { try { JYTHON_MODEL_CLASS = Class.forName("freemarker.ext.jython.JythonModel"); } catch (Throwable e) { JYTHON_MODEL_CLASS = null; } } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); String classname = null; try { classname = ((TemplateScalarModel) tm).getAsString(); } catch (ClassCastException cce) { invalidTypeException(tm, target, env, "string"); } catch (NullPointerException npe) { throw new InvalidReferenceException(getStartLocation() + "\nCould not resolve expression: " + target, env); } return new ConstructorFunction(classname, env, target.getTemplate()); } static class ConstructorFunction implements TemplateMethodModelEx { private final Class cl; private final Environment env; public ConstructorFunction(String classname, Environment env, Template template) throws TemplateException { this.env = env; cl = env.getNewBuiltinClassResolver().resolve(classname, env, template); if (!TM_CLASS.isAssignableFrom(cl)) { throw new TemplateException("Class " + cl.getName() + " does not implement freemarker.template.TemplateModel", env); } if (BEAN_MODEL_CLASS.isAssignableFrom(cl)) { throw new TemplateException("Bean Models cannot be instantiated using the ?new built-in", env); } if (JYTHON_MODEL_CLASS != null && JYTHON_MODEL_CLASS.isAssignableFrom(cl)) { throw new TemplateException("Jython Models cannot be instantiated using the ?new built-in", env); } } public Object exec(List arguments) throws TemplateModelException { ObjectWrapper ow = env.getObjectWrapper(); BeansWrapper bw = ow instanceof BeansWrapper ? (BeansWrapper)ow : BeansWrapper.getDefaultInstance(); return bw.newInstance(cl, arguments); } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NonBooleanException.java0000644000175000017500000000613611723544471026262 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; /** * A subclass of TemplateException that * indicates that the internals expected an expression * to evaluate to a boolean value and it didn't. * @author Jonathan Revusky */ public class NonBooleanException extends TemplateException { public NonBooleanException(Environment env) { super("expecting boolean value here", env); } public NonBooleanException(String description, Environment env) { super(description, env); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/StopException.java0000644000175000017500000000704511723544470025154 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.PrintWriter; import java.io.PrintStream; import freemarker.template.TemplateException; /** * This exception is thrown when a <stop> * directive is encountered. */ public class StopException extends TemplateException { StopException(Environment env) { super(env); } StopException(Environment env, String s) { super(s, env); } public void printStackTrace(PrintWriter pw) { String msg = this.getMessage(); pw.print("Encountered stop instruction"); if (msg != null && !msg.equals("")) { pw.println("\nCause given: " + msg); } else pw.println(); super.printStackTrace(pw); } public void printStackTrace(PrintStream ps) { String msg = this.getMessage(); ps.print("Encountered stop instruction"); if (msg != null && !msg.equals("")) { ps.println("\nCause given: " + msg); } else ps.println(); super.printStackTrace(ps); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Comment.java0000644000175000017500000000626511723544470023755 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; /** * A template element where the content is ignored, a Comment. */ public final class Comment extends TemplateElement { private final String text; Comment(String text) { this.text = text; } void accept(Environment env) { // do nothing, skip the body } public String getCanonicalForm() { return "<#--" + text + "-->"; } public String getDescription() { String s = text.trim(); if (s.length() > 20) { s = s.substring(0, 20) + "..."; } return "comment (" + s + ")"; } public String getText() { return text; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TextBlock.java0000644000175000017500000003615511723544467024261 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; /** * A TemplateElement representing a block of plain text. * @version $Id: TextBlock.java,v 1.17 2004/01/06 17:06:42 szegedia Exp $ */ public final class TextBlock extends TemplateElement { private static final char[] EMPTY_CHAR_ARRAY = new char[0]; static final TextBlock EMPTY_BLOCK = new TextBlock(EMPTY_CHAR_ARRAY, false); // We're using char[] instead of String for storing the text block because // Writer.write(String) involves copying the String contents to a char[] // using String.getChars(), and then calling Writer.write(char[]). By // using Writer.write(char[]) directly, we avoid array copying on each // write. private char[] text; private final boolean unparsed; public TextBlock(String text) { this(text, false); } public TextBlock(String text, boolean unparsed) { this(text.toCharArray(), unparsed); } private TextBlock(char[] text, boolean unparsed) { this.text = text; this.unparsed = unparsed; } /** * Simply outputs the text. */ public void accept(Environment env) throws IOException { env.getOut().write(text); } public String getCanonicalForm() { String text = new String(this.text); if (unparsed) { return "<#noparse>" + text + ""; } return text; } public String getDescription() { String s = new String(text).trim(); if (s.length() == 0) { return "whitespace"; } if (s.length() > 20) { s = s.substring(0,20) + "..."; s = s.replace('\n', ' '); s = s.replace('\r', ' '); } return "text block (" + s + ")"; } TemplateElement postParseCleanup(boolean stripWhitespace) { if (text.length == 0) return this; int openingCharsToStrip = 0, trailingCharsToStrip=0; boolean deliberateLeftTrim = deliberateLeftTrim(); boolean deliberateRightTrim = deliberateRightTrim(); if (!stripWhitespace || text.length == 0 ) { return this; } if (parent.parent == null && previousSibling() == null) return this; if (!deliberateLeftTrim) { trailingCharsToStrip = trailingCharsToStrip(); } if (!deliberateRightTrim) { openingCharsToStrip = openingCharsToStrip(); } if (openingCharsToStrip == 0 && trailingCharsToStrip == 0) { return this; } this.text = substring(text, openingCharsToStrip, text.length - trailingCharsToStrip); if (openingCharsToStrip > 0) { this.beginLine++; this.beginColumn = 1; } if (trailingCharsToStrip >0) { this.endColumn = 0; } return this; } /** * Scans forward the nodes on the same line to see whether there is a * deliberate left trim in effect. Returns true if the left trim was present. */ private boolean deliberateLeftTrim() { boolean result = false; for (TemplateElement elem = this.nextTerminalNode(); elem != null && elem.beginLine == this.endLine; elem = elem.nextTerminalNode()) { if (elem instanceof TrimInstruction) { TrimInstruction ti = (TrimInstruction) elem; if (!ti.left && !ti.right) { result = true; } if (ti.left) { result = true; int lastNewLineIndex = lastNewLineIndex(); if (lastNewLineIndex >=0 || beginColumn == 1) { char[] firstPart = substring(text, 0, lastNewLineIndex + 1); char[] lastLine = substring(text, 1+lastNewLineIndex); if (trim(lastLine).length == 0) { this.text = firstPart; this.endColumn = 0; } else { int i =0; while (Character.isWhitespace(lastLine[i])) { i++; } char[] printablePart = substring(lastLine, i); this.text = concat(firstPart, printablePart); } } } } } if (result) { } return result; } /** * Checks for the presence of a t or rt directive on the * same line. Returns true if the right trim directive was present. */ private boolean deliberateRightTrim() { boolean result = false; for (TemplateElement elem = this.prevTerminalNode(); elem != null && elem.endLine == this.beginLine; elem = elem.prevTerminalNode()) { if (elem instanceof TrimInstruction) { TrimInstruction ti = (TrimInstruction) elem; if (!ti.left && !ti.right) { result = true; } if (ti.right) { result = true; int firstLineIndex = firstNewLineIndex() +1; if (firstLineIndex == 0) { return false; } if (text.length > firstLineIndex && text[firstLineIndex-1] == '\r' && text[firstLineIndex] == '\n') { firstLineIndex++; } char[] trailingPart = substring(text, firstLineIndex); char[] openingPart = substring(text, 0, firstLineIndex); if (trim(openingPart).length ==0) { this.text = trailingPart; this.beginLine++; this.beginColumn=1; } else { int lastNonWS = openingPart.length -1; while (Character.isWhitespace(text[lastNonWS])) { lastNonWS--; } char[] printablePart = substring(text, 0, lastNonWS+1); if (trim(trailingPart).length == 0) { // THIS BLOCK IS HEINOUS! THERE MUST BE A BETTER WAY! REVISIT (JR) boolean trimTrailingPart = true; for (TemplateElement te = this.nextTerminalNode(); te != null && te.beginLine == this.endLine; te = te.nextTerminalNode()) { if (te.heedsOpeningWhitespace()) { trimTrailingPart = false; } if (te instanceof TrimInstruction && ((TrimInstruction) te).left) { trimTrailingPart = true; break; } } if (trimTrailingPart) trailingPart = EMPTY_CHAR_ARRAY; } this.text = concat(printablePart, trailingPart); } } } } return result; } /* private String leftTrim(String s) { int i =0; while (i=0 ? newlineIndex1 : newlineIndex2; if (newlineIndex1 >=0 && newlineIndex2 >=0) { result = Math.min(newlineIndex1, newlineIndex2); } return result; } private int lastNewLineIndex() { String content = new String(text); return Math.max(content.lastIndexOf('\r'), content.lastIndexOf('\n')); } /** * figures out how many opening whitespace characters to strip * in the post-parse cleanup phase. */ private int openingCharsToStrip() { int newlineIndex = firstNewLineIndex(); if (newlineIndex == -1 && beginColumn != 1) { return 0; } ++newlineIndex; if (text.length > newlineIndex) { if (newlineIndex >0 && text[newlineIndex-1] == '\r' && text[newlineIndex] == '\n') { ++newlineIndex; } } if (new String(text).substring(0, newlineIndex).trim().length() >0) { return 0; } // We look at the preceding elements on the line to see if we should // strip the opening newline and any whitespace preceding it. for (TemplateElement elem = this.prevTerminalNode(); elem != null && elem.endLine == this.beginLine; elem = elem.prevTerminalNode()) { if (elem.heedsOpeningWhitespace()) { return 0; } } return newlineIndex; } /** * figures out how many trailing whitespace characters to strip * in the post-parse cleanup phase. */ private int trailingCharsToStrip() { String content = new String(text); int lastNewlineIndex = lastNewLineIndex(); if (lastNewlineIndex == -1 && beginColumn != 1) { return 0; } String substring = content.substring(lastNewlineIndex +1); if (substring.trim().length() >0) { return 0; } // We look at the elements afterward on the same line to see if we should // strip any whitespace after the last newline for (TemplateElement elem = this.nextTerminalNode(); elem != null && elem.beginLine == this.endLine; elem = elem.nextTerminalNode()) { if (elem.heedsTrailingWhitespace()) { return 0; } } return substring.length(); } boolean heedsTrailingWhitespace() { if (isIgnorable()) { return false; } for (int i=0; i=0; i--) { char c = text[i]; if (c == '\n' || c == '\r') { return false; } if (!Character.isWhitespace(c)) { return true; } } return true; } boolean isIgnorable() { if (text == null || text.length == 0) { return true; } if (!isWhitespace()) { return false; } boolean atTopLevel = (getParent().getParent() == null); TemplateElement prevSibling = previousSibling(); TemplateElement nextSibling = nextSibling(); return ((prevSibling == null && atTopLevel) || nonOutputtingType(prevSibling)) && ((nextSibling == null && atTopLevel) || nonOutputtingType(nextSibling)); } private boolean nonOutputtingType(TemplateElement element) { return (element instanceof Macro || element instanceof Assignment || element instanceof AssignmentInstruction || element instanceof PropertySetting || element instanceof LibraryLoad || element instanceof Comment); } private static char[] substring(char[] c, int from, int to) { char[] c2 = new char[to - from]; System.arraycopy(c, from, c2, 0, c2.length); return c2; } private static char[] substring(char[] c, int from) { return substring(c, from, c.length); } private static char[] trim(char[] c) { if (c.length == 0) { return c; } return new String(c).trim().toCharArray(); } private static char[] concat(char[] c1, char[] c2) { char[] c = new char[c1.length + c2.length]; System.arraycopy(c1, 0, c, 0, c1.length); System.arraycopy(c2, 0, c, c1.length, c2.length); return c; } boolean isWhitespace() { return text == null || trim(text).length == 0; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ConditionalBlock.java0000644000175000017500000001036011723544470025560 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.*; /** * An element that represents a conditionally executed block. * @author Jonathan Revusky */ final class ConditionalBlock extends TemplateElement { final Expression condition; private final boolean isFirst; boolean isSimple; ConditionalBlock(Expression condition, TemplateElement nestedBlock, boolean isFirst) { this.condition = condition; this.nestedBlock = nestedBlock; this.isFirst = isFirst; } void accept(Environment env) throws TemplateException, IOException { if (condition == null || condition.isTrue(env)) { if (nestedBlock != null) { env.visit(nestedBlock); } } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer(); if (condition == null) { buf.append("<#else"); } else if (isFirst) { buf.append("<#if "); } else { buf.append("<#elseif "); } if (condition != null) { buf.append(condition.getCanonicalForm()); } buf.append(">"); if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } if (isSimple) { buf.append(""); } return buf.toString(); } public String getDescription() { String s = "if "; if (condition == null) { s = "else "; } else if (!isFirst) { s = "elseif "; } String cond = condition != null ? condition.toString() : ""; return s + cond; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Environment.java0000644000175000017500000017633011723544472024662 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.*; import java.text.*; import java.util.*; import freemarker.ext.beans.BeansWrapper; import freemarker.log.Logger; import freemarker.template.*; import freemarker.template.utility.DateUtil; import freemarker.template.utility.DateUtil.DateToISO8601CalendarFactory; import freemarker.template.utility.StringUtil; import freemarker.template.utility.UndeclaredThrowableException; /** * Object that represents the runtime environment during template processing. * For every invocation of a Template.process() method, a new instance * of this object is created, and then discarded when process() returns. * This object stores the set of temporary variables created by the template, * the value of settings set by the template, the reference to the data model root, * etc. Everything that is needed to fulfill the template processing job. * *

Data models that need to access the Environment * object that represents the template processing on the current thread can use * the {@link #getCurrentEnvironment()} method. * *

If you need to modify or read this object before or after the process * call, use {@link Template#createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper)} * * @author Jonathan Revusky * @author Attila Szegedi */ public final class Environment extends Configurable { private static final ThreadLocal threadEnv = new ThreadLocal(); private static final Logger logger = Logger.getLogger("freemarker.runtime"); private static final Logger attemptLogger = Logger.getLogger("freemarker.runtime.attempt"); private static final Map localizedNumberFormats = new HashMap(); private static final Map localizedDateFormats = new HashMap(); // Do not use this object directly; clone it first! DecimalFormat isn't // thread-safe. private static final DecimalFormat C_NUMBER_FORMAT = new DecimalFormat( "0.################", new DecimalFormatSymbols(Locale.US)); static { C_NUMBER_FORMAT.setGroupingUsed(false); C_NUMBER_FORMAT.setDecimalSeparatorAlwaysShown(false); } private final TemplateHashModel rootDataModel; private final ArrayList elementStack = new ArrayList(); private final ArrayList recoveredErrorStack = new ArrayList(); private NumberFormat numberFormat; private Map numberFormats; private DateFormat timeFormat, dateFormat, dateTimeFormat; private Map[] dateFormats; private NumberFormat cNumberFormat; /** * Used by the "iso_" built-ins to accelerate formatting. * @see #getISOBuiltInCalendar() */ private DateToISO8601CalendarFactory isoBuiltInCalendarFactory; private Collator collator; private Writer out; private Macro.Context currentMacroContext; private ArrayList localContextStack; private Namespace mainNamespace, currentNamespace, globalNamespace; private HashMap loadedLibs; private Throwable lastThrowable; private TemplateModel lastReturnValue; private HashMap macroToNamespaceLookup = new HashMap(); private TemplateNodeModel currentVisitorNode; private TemplateSequenceModel nodeNamespaces; // Things we keep track of for the fallback mechanism. private int nodeNamespaceIndex; private String currentNodeName, currentNodeNS; private String cachedURLEscapingCharset; private boolean urlEscapingCharsetCached; /** * Retrieves the environment object associated with the current * thread. Data model implementations that need access to the * environment can call this method to obtain the environment object * that represents the template processing that is currently running * on the current thread. */ public static Environment getCurrentEnvironment() { return (Environment)threadEnv.get(); } public Environment(Template template, final TemplateHashModel rootDataModel, Writer out) { super(template); this.globalNamespace = new Namespace(null); this.currentNamespace = mainNamespace = new Namespace(template); this.out = out; this.rootDataModel = rootDataModel; importMacros(template); } /** * Retrieves the currently processed template. */ public Template getTemplate() { return (Template)getParent(); } /** * Deletes cached values that meant to be valid only during a single * template execution. */ private void clearCachedValues() { numberFormats = null; numberFormat = null; dateFormats = null; collator = null; cachedURLEscapingCharset = null; urlEscapingCharsetCached = false; } /** * Processes the template to which this environment belongs. */ public void process() throws TemplateException, IOException { Object savedEnv = threadEnv.get(); threadEnv.set(this); try { // Cached values from a previous execution are possibly outdated. clearCachedValues(); try { doAutoImportsAndIncludes(this); visit(getTemplate().getRootTreeNode()); // It's here as we must not flush if there was an exception. if (getAutoFlush()) { out.flush(); } } finally { // It's just to allow the GC to free memory... clearCachedValues(); } } finally { threadEnv.set(savedEnv); } } /** * "Visit" the template element. */ void visit(TemplateElement element) throws TemplateException, IOException { pushElement(element); try { element.accept(this); } catch (TemplateException te) { handleTemplateException(te); } finally { popElement(); } } private static final TemplateModel[] NO_OUT_ARGS = new TemplateModel[0]; public void visit(final TemplateElement element, TemplateDirectiveModel directiveModel, Map args, final List bodyParameterNames) throws TemplateException, IOException { TemplateDirectiveBody nested; if(element == null) { nested = null; } else { nested = new TemplateDirectiveBody() { public void render(Writer newOut) throws TemplateException, IOException { Writer prevOut = out; out = newOut; try { Environment.this.visit(element); } finally { out = prevOut; } } }; } final TemplateModel[] outArgs; if(bodyParameterNames == null || bodyParameterNames.isEmpty()) { outArgs = NO_OUT_ARGS; } else { outArgs = new TemplateModel[bodyParameterNames.size()]; } if(outArgs.length > 0) { pushLocalContext(new LocalContext() { public TemplateModel getLocalVariable(String name) { int index = bodyParameterNames.indexOf(name); return index != -1 ? outArgs[index] : null; } public Collection getLocalVariableNames() { return bodyParameterNames; } }); } try { directiveModel.execute(this, args, outArgs, nested); } finally { if(outArgs.length > 0) { popLocalContext(); } } } /** * "Visit" the template element, passing the output * through a TemplateTransformModel * @param element the element to visit through a transform * @param transform the transform to pass the element output * through * @param args optional arguments fed to the transform */ void visit(TemplateElement element, TemplateTransformModel transform, Map args) throws TemplateException, IOException { try { Writer tw = transform.getWriter(out, args); if (tw == null) tw = EMPTY_BODY_WRITER; TransformControl tc = tw instanceof TransformControl ? (TransformControl)tw : null; Writer prevOut = out; out = tw; try { if(tc == null || tc.onStart() != TransformControl.SKIP_BODY) { do { if(element != null) { visit(element); } } while(tc != null && tc.afterBody() == TransformControl.REPEAT_EVALUATION); } } catch(Throwable t) { try { if(tc != null) { tc.onError(t); } else { throw t; } } catch(TemplateException e) { throw e; } catch(IOException e) { throw e; } catch(RuntimeException e) { throw e; } catch(Error e) { throw e; } catch(Throwable e) { throw new UndeclaredThrowableException(e); } } finally { out = prevOut; tw.close(); } } catch(TemplateException te) { handleTemplateException(te); } } /** * Visit a block using buffering/recovery */ void visit(TemplateElement attemptBlock, TemplateElement recoveryBlock) throws TemplateException, IOException { Writer prevOut = this.out; StringWriter sw = new StringWriter(); this.out = sw; TemplateException thrownException = null; try { visit(attemptBlock); } catch (TemplateException te) { thrownException = te; } finally { this.out = prevOut; } if (thrownException != null) { if (attemptLogger.isDebugEnabled()) { attemptLogger.debug("Error in attempt block " + attemptBlock.getStartLocationQuoted(), thrownException); } try { recoveredErrorStack.add(thrownException.getMessage()); visit(recoveryBlock); } finally { recoveredErrorStack.remove(recoveredErrorStack.size() -1); } } else { out.write(sw.toString()); } } String getCurrentRecoveredErrorMesssage() throws TemplateException { if(recoveredErrorStack.isEmpty()) { throw new TemplateException( ".error is not available outside of a <#recover> block", this); } return (String) recoveredErrorStack.get(recoveredErrorStack.size() -1); } void visit(BodyInstruction.Context bctxt) throws TemplateException, IOException { Macro.Context invokingMacroContext = getCurrentMacroContext(); ArrayList prevLocalContextStack = localContextStack; TemplateElement body = invokingMacroContext.body; if (body != null) { this.currentMacroContext = invokingMacroContext.prevMacroContext; currentNamespace = invokingMacroContext.bodyNamespace; Configurable prevParent = getParent(); setParent(currentNamespace.getTemplate()); this.localContextStack = invokingMacroContext.prevLocalContextStack; if (invokingMacroContext.bodyParameterNames != null) { pushLocalContext(bctxt); } try { visit(body); } finally { if (invokingMacroContext.bodyParameterNames != null) { popLocalContext(); } this.currentMacroContext = invokingMacroContext; currentNamespace = getMacroNamespace(invokingMacroContext.getMacro()); setParent(prevParent); this.localContextStack = prevLocalContextStack; } } } /** * "visit" an IteratorBlock */ void visit(IteratorBlock.Context ictxt) throws TemplateException, IOException { pushLocalContext(ictxt); try { ictxt.runLoop(this); } catch (BreakInstruction.Break br) { } catch (TemplateException te) { handleTemplateException(te); } finally { popLocalContext(); } } /** * "Visit" A TemplateNodeModel */ void visit(TemplateNodeModel node, TemplateSequenceModel namespaces) throws TemplateException, IOException { if (nodeNamespaces == null) { SimpleSequence ss = new SimpleSequence(1); ss.add(currentNamespace); nodeNamespaces = ss; } int prevNodeNamespaceIndex = this.nodeNamespaceIndex; String prevNodeName = this.currentNodeName; String prevNodeNS = this.currentNodeNS; TemplateSequenceModel prevNodeNamespaces = nodeNamespaces; TemplateNodeModel prevVisitorNode = currentVisitorNode; currentVisitorNode = node; if (namespaces != null) { this.nodeNamespaces = namespaces; } try { TemplateModel macroOrTransform = getNodeProcessor(node); if (macroOrTransform instanceof Macro) { visit((Macro) macroOrTransform, null, null, null, null); } else if (macroOrTransform instanceof TemplateTransformModel) { visit(null, (TemplateTransformModel) macroOrTransform, null); } else { String nodeType = node.getNodeType(); if (nodeType != null) { // If the node's type is 'text', we just output it. if ((nodeType.equals("text") && node instanceof TemplateScalarModel)) { out.write(((TemplateScalarModel) node).getAsString()); } else if (nodeType.equals("document")) { recurse(node, namespaces); } // We complain here, unless the node's type is 'pi', or "comment" or "document_type", in which case // we just ignore it. else if (!nodeType.equals("pi") && !nodeType.equals("comment") && !nodeType.equals("document_type")) { String nsBit = ""; String ns = node.getNodeNamespace(); if (ns != null) { if (ns.length() >0) { nsBit = " and namespace " + ns; } else { nsBit = " and no namespace"; } } throw new TemplateException("No macro or transform defined for node named " + node.getNodeName() + nsBit + ", and there is no fallback handler called @" + nodeType + " either.", this); } } else { String nsBit = ""; String ns = node.getNodeNamespace(); if (ns != null) { if (ns.length() >0) { nsBit = " and namespace " + ns; } else { nsBit = " and no namespace"; } } throw new TemplateException("No macro or transform defined for node with name " + node.getNodeName() + nsBit + ", and there is no macro or transform called @default either.", this); } } } finally { this.currentVisitorNode = prevVisitorNode; this.nodeNamespaceIndex = prevNodeNamespaceIndex; this.currentNodeName = prevNodeName; this.currentNodeNS = prevNodeNS; this.nodeNamespaces = prevNodeNamespaces; } } void fallback() throws TemplateException, IOException { TemplateModel macroOrTransform = getNodeProcessor(currentNodeName, currentNodeNS, nodeNamespaceIndex); if (macroOrTransform instanceof Macro) { visit((Macro) macroOrTransform, null, null, null, null); } else if (macroOrTransform instanceof TemplateTransformModel) { visit(null, (TemplateTransformModel) macroOrTransform, null); } } /** * "visit" a macro. */ void visit(Macro macro, Map namedArgs, List positionalArgs, List bodyParameterNames, TemplateElement nestedBlock) throws TemplateException, IOException { if (macro == Macro.DO_NOTHING_MACRO) { return; } pushElement(macro); try { Macro.Context previousMacroContext = currentMacroContext; Macro.Context mc = macro.new Context(this, nestedBlock, bodyParameterNames); String catchAll = macro.getCatchAll(); TemplateModel unknownVars = null; if (namedArgs != null) { if (catchAll != null) unknownVars = new SimpleHash(); for (Iterator it = namedArgs.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String varName = (String) entry.getKey(); boolean hasVar = macro.hasArgNamed(varName); if (hasVar || catchAll != null) { Expression arg = (Expression) entry.getValue(); TemplateModel value = arg.getAsTemplateModel(this); if (hasVar) { mc.setLocalVar(varName, value); } else { ((SimpleHash)unknownVars).put(varName, value); } } else { String msg = "Macro " + macro.getName() + " has no such argument: " + varName; throw new TemplateException(msg, this); } } } else if (positionalArgs != null) { if (catchAll != null) unknownVars = new SimpleSequence(); String[] argumentNames = macro.getArgumentNamesInternal(); int size = positionalArgs.size(); if (argumentNames.length < size && catchAll == null) { throw new TemplateException("Macro " + macro.getName() + " only accepts " + argumentNames.length + " parameters.", this); } for (int i = 0; i < size; i++) { Expression argExp = (Expression) positionalArgs.get(i); TemplateModel argModel = argExp.getAsTemplateModel(this); try { if (i < argumentNames.length) { String argName = argumentNames[i]; mc.setLocalVar(argName, argModel); } else { ((SimpleSequence)unknownVars).add(argModel); } } catch (RuntimeException re) { throw new TemplateException(re, this); } } } if (catchAll != null) { mc.setLocalVar(catchAll, unknownVars); } ArrayList prevLocalContextStack = localContextStack; localContextStack = null; Namespace prevNamespace = currentNamespace; Configurable prevParent = getParent(); currentNamespace = (Namespace) macroToNamespaceLookup.get(macro); currentMacroContext = mc; try { mc.runMacro(this); } catch (ReturnInstruction.Return re) { } catch (TemplateException te) { handleTemplateException(te); } finally { currentMacroContext = previousMacroContext; localContextStack = prevLocalContextStack; currentNamespace = prevNamespace; setParent(prevParent); } } finally { popElement(); } } void visitMacroDef(Macro macro) { macroToNamespaceLookup.put(macro, currentNamespace); currentNamespace.put(macro.getName(), macro); } Namespace getMacroNamespace(Macro macro) { return (Namespace) macroToNamespaceLookup.get(macro); } void recurse(TemplateNodeModel node, TemplateSequenceModel namespaces) throws TemplateException, IOException { if (node == null) { node = this.getCurrentVisitorNode(); if (node == null) { throw new TemplateModelException( "The target node of recursion is missing or null."); } } TemplateSequenceModel children = node.getChildNodes(); if (children == null) return; for (int i=0; isetting directive, it still must be allowed to set it from Java * code while the template executes, since some frameworks allow templates * to actually change the output encoding on-the-fly. */ public void setOutputEncoding(String outputEncoding) { urlEscapingCharsetCached = false; super.setOutputEncoding(outputEncoding); } /** * Returns the name of the charset that should be used for URL encoding. * This will be null if the information is not available. * The function caches the return value, so it is quick to call it * repeately. */ String getEffectiveURLEscapingCharset() { if (!urlEscapingCharsetCached) { cachedURLEscapingCharset = getURLEscapingCharset(); if (cachedURLEscapingCharset == null) { cachedURLEscapingCharset = getOutputEncoding(); } urlEscapingCharsetCached = true; } return cachedURLEscapingCharset; } Collator getCollator() { if(collator == null) { collator = Collator.getInstance(getLocale()); } return collator; } public void setOut(Writer out) { this.out = out; } public Writer getOut() { return out; } String formatNumber(Number number) { if(numberFormat == null) { numberFormat = getNumberFormatObject(getNumberFormat()); } return numberFormat.format(number); } public void setNumberFormat(String formatName) { super.setNumberFormat(formatName); numberFormat = null; } String formatDate(Date date, int type) throws TemplateModelException { DateFormat df = getDateFormatObject(type); if(df == null) { throw new TemplateModelException("Can't convert the date to string, because it is not known which parts of the date variable are in use. Use ?date, ?time or ?datetime built-in, or ?string. or ?string(format) built-in with this date."); } return df.format(date); } public void setTimeFormat(String formatName) { super.setTimeFormat(formatName); timeFormat = null; } public void setDateFormat(String formatName) { super.setDateFormat(formatName); dateFormat = null; } public void setDateTimeFormat(String formatName) { super.setDateTimeFormat(formatName); dateTimeFormat = null; } public Configuration getConfiguration() { return getTemplate().getConfiguration(); } TemplateModel getLastReturnValue() { return lastReturnValue; } void setLastReturnValue(TemplateModel lastReturnValue) { this.lastReturnValue = lastReturnValue; } void clearLastReturnValue() { this.lastReturnValue = null; } NumberFormat getNumberFormatObject(String pattern) { if(numberFormats == null) { numberFormats = new HashMap(); } NumberFormat format = (NumberFormat) numberFormats.get(pattern); if(format != null) { return format; } // Get format from global format cache synchronized(localizedNumberFormats) { Locale locale = getLocale(); NumberFormatKey fk = new NumberFormatKey(pattern, locale); format = (NumberFormat)localizedNumberFormats.get(fk); if(format == null) { // Add format to global format cache. Note this is // globally done once per locale per pattern. if("number".equals(pattern)) { format = NumberFormat.getNumberInstance(locale); } else if("currency".equals(pattern)) { format = NumberFormat.getCurrencyInstance(locale); } else if("percent".equals(pattern)) { format = NumberFormat.getPercentInstance(locale); } else if ("computer".equals(pattern)) { format = getCNumberFormat(); } else { format = new DecimalFormat(pattern, new DecimalFormatSymbols(getLocale())); } localizedNumberFormats.put(fk, format); } } // Clone it and store the clone in the local cache format = (NumberFormat)format.clone(); numberFormats.put(pattern, format); return format; } DateFormat getDateFormatObject(int dateType) throws TemplateModelException { switch(dateType) { case TemplateDateModel.UNKNOWN: { return null; } case TemplateDateModel.TIME: { if(timeFormat == null) { timeFormat = getDateFormatObject(dateType, getTimeFormat()); } return timeFormat; } case TemplateDateModel.DATE: { if(dateFormat == null) { dateFormat = getDateFormatObject(dateType, getDateFormat()); } return dateFormat; } case TemplateDateModel.DATETIME: { if(dateTimeFormat == null) { dateTimeFormat = getDateFormatObject(dateType, getDateTimeFormat()); } return dateTimeFormat; } default: { throw new TemplateModelException("Unrecognized date type " + dateType); } } } DateFormat getDateFormatObject(int dateType, String pattern) throws TemplateModelException { if(dateFormats == null) { dateFormats = new Map[4]; dateFormats[TemplateDateModel.UNKNOWN] = new HashMap(); dateFormats[TemplateDateModel.TIME] = new HashMap(); dateFormats[TemplateDateModel.DATE] = new HashMap(); dateFormats[TemplateDateModel.DATETIME] = new HashMap(); } Map typedDateFormat = dateFormats[dateType]; DateFormat format = (DateFormat) typedDateFormat.get(pattern); if(format != null) { return format; } // Get format from global format cache synchronized(localizedDateFormats) { Locale locale = getLocale(); TimeZone timeZone = getTimeZone(); DateFormatKey fk = new DateFormatKey(dateType, pattern, locale, timeZone); format = (DateFormat)localizedDateFormats.get(fk); if(format == null) { // Add format to global format cache. Note this is // globally done once per locale per pattern. StringTokenizer tok = new StringTokenizer(pattern, "_"); int style = tok.hasMoreTokens() ? parseDateStyleToken(tok.nextToken()) : DateFormat.DEFAULT; if(style != -1) { switch(dateType) { case TemplateDateModel.UNKNOWN: { throw new TemplateModelException( "Can't convert the date to string using a " + "built-in format, because it is not known which " + "parts of the date variable are in use. Use " + "?date, ?time or ?datetime built-in, or " + "?string. or ?string() built-in "+ "with explicit formatting pattern with this date."); } case TemplateDateModel.TIME: { format = DateFormat.getTimeInstance(style, locale); break; } case TemplateDateModel.DATE: { format = DateFormat.getDateInstance(style, locale); break; } case TemplateDateModel.DATETIME: { int timestyle = tok.hasMoreTokens() ? parseDateStyleToken(tok.nextToken()) : style; if(timestyle != -1) { format = DateFormat.getDateTimeInstance(style, timestyle, locale); } break; } } } if(format == null) { try { format = new SimpleDateFormat(pattern, locale); } catch(IllegalArgumentException e) { throw new TemplateModelException("Can't parse " + pattern + " to a date format.", e); } } format.setTimeZone(timeZone); localizedDateFormats.put(fk, format); } } // Clone it and store the clone in the local cache format = (DateFormat)format.clone(); typedDateFormat.put(pattern, format); return format; } int parseDateStyleToken(String token) { if("short".equals(token)) { return DateFormat.SHORT; } if("medium".equals(token)) { return DateFormat.MEDIUM; } if("long".equals(token)) { return DateFormat.LONG; } if("full".equals(token)) { return DateFormat.FULL; } return -1; } /** * Returns the {@link DateUtil.DateToISO8601CalendarFactory} used by the * the "iso_" built-ins. Be careful when using this; it should only by used * with {@link DateUtil#dateToISO8601String(Date, boolean, boolean, boolean, * int, TimeZone, DateToISO8601CalendarFactory)}. */ DateToISO8601CalendarFactory getISOBuiltInCalendar() { if (isoBuiltInCalendarFactory == null) { isoBuiltInCalendarFactory = new DateUtil.TrivialDateToISO8601CalendarFactory(); } return isoBuiltInCalendarFactory; } /** * Returns the {@link NumberFormat} used for the c built-in. * This is always US English "0.################", without * grouping and without superfluous decimal separator. */ public NumberFormat getCNumberFormat() { // It can't be cached in a static field, because DecimalFormat-s aren't // thread-safe. if (cNumberFormat == null) { cNumberFormat = (DecimalFormat) C_NUMBER_FORMAT.clone(); } return cNumberFormat; } TemplateTransformModel getTransform(Expression exp) throws TemplateException { TemplateTransformModel ttm = null; TemplateModel tm = exp.getAsTemplateModel(this); if (tm instanceof TemplateTransformModel) { ttm = (TemplateTransformModel) tm; } else if (exp instanceof Identifier) { tm = getConfiguration().getSharedVariable(exp.toString()); if (tm instanceof TemplateTransformModel) { ttm = (TemplateTransformModel) tm; } } return ttm; } /** * Returns the loop or macro local variable corresponding to this * variable name. Possibly null. * (Note that the misnomer is kept for backward compatibility: loop variables * are not local variables according to our terminology.) */ public TemplateModel getLocalVariable(String name) throws TemplateModelException { if (localContextStack != null) { for (int i = localContextStack.size()-1; i>=0; i--) { LocalContext lc = (LocalContext) localContextStack.get(i); TemplateModel tm = lc.getLocalVariable(name); if (tm != null) { return tm; } } } return currentMacroContext == null ? null : currentMacroContext.getLocalVariable(name); } /** * Returns the variable that is visible in this context. * This is the correspondent to an FTL top-level variable reading expression. * That is, it tries to find the the variable in this order: *

    *
  1. An loop variable (if we're in a loop or user defined directive body) such as foo_has_next *
  2. A local variable (if we're in a macro) *
  3. A variable defined in the current namespace (say, via <#assign ...>) *
  4. A variable defined globally (say, via <#global ....>) *
  5. Variable in the data model: *
      *
    1. A variable in the root hash that was exposed to this rendering environment in the Template.process(...) call *
    2. A shared variable set in the configuration via a call to Configuration.setSharedVariable(...) *
    *
  6. *
*/ public TemplateModel getVariable(String name) throws TemplateModelException { TemplateModel result = getLocalVariable(name); if (result == null) { result = currentNamespace.get(name); } if (result == null) { result = getGlobalVariable(name); } return result; } /** * Returns the globally visible variable of the given name (or null). * This is correspondent to FTL .globals.name. * This will first look at variables that were assigned globally via: * <#global ...> and then at the data model exposed to the template. */ public TemplateModel getGlobalVariable(String name) throws TemplateModelException { TemplateModel result = globalNamespace.get(name); if (result == null) { result = rootDataModel.get(name); } if (result == null) { result = getConfiguration().getSharedVariable(name); } return result; } /** * Sets a variable that is visible globally. * This is correspondent to FTL <#global name=model>. * This can be considered a convenient shorthand for: * getGlobalNamespace().put(name, model) */ public void setGlobalVariable(String name, TemplateModel model) { globalNamespace.put(name, model); } /** * Sets a variable in the current namespace. * This is correspondent to FTL <#assign name=model>. * This can be considered a convenient shorthand for: * getCurrentNamespace().put(name, model) */ public void setVariable(String name, TemplateModel model) { currentNamespace.put(name, model); } /** * Sets a local variable (one effective only during a macro invocation). * This is correspondent to FTL <#local name=model>. * @param name the identifier of the variable * @param model the value of the variable. * @throws IllegalStateException if the environment is not executing a * macro body. */ public void setLocalVariable(String name, TemplateModel model) { if(currentMacroContext == null) { throw new IllegalStateException("Not executing macro body"); } currentMacroContext.setLocalVar(name, model); } /** * Returns a set of variable names that are known at the time of call. This * includes names of all shared variables in the {@link Configuration}, * names of all global variables that were assigned during the template processing, * names of all variables in the current name-space, names of all local variables * and loop variables. If the passed root data model implements the * {@link TemplateHashModelEx} interface, then all names it retrieves through a call to * {@link TemplateHashModelEx#keys()} method are returned as well. * The method returns a new Set object on each call that is completely * disconnected from the Environment. That is, modifying the set will have * no effect on the Environment object. */ public Set getKnownVariableNames() throws TemplateModelException { // shared vars. Set set = getConfiguration().getSharedVariableNames(); // root hash if (rootDataModel instanceof TemplateHashModelEx) { TemplateModelIterator rootNames = ((TemplateHashModelEx) rootDataModel).keys().iterator(); while(rootNames.hasNext()) { set.add(((TemplateScalarModel)rootNames.next()).getAsString()); } } // globals for (TemplateModelIterator tmi = globalNamespace.keys().iterator(); tmi.hasNext();) { set.add(((TemplateScalarModel) tmi.next()).getAsString()); } // current name-space for (TemplateModelIterator tmi = currentNamespace.keys().iterator(); tmi.hasNext();) { set.add(((TemplateScalarModel) tmi.next()).getAsString()); } // locals and loop vars if(currentMacroContext != null) { set.addAll(currentMacroContext.getLocalVariableNames()); } if (localContextStack != null) { for (int i = localContextStack.size()-1; i>=0; i--) { LocalContext lc = (LocalContext) localContextStack.get(i); set.addAll(lc.getLocalVariableNames()); } } return set; } /** * Outputs the instruction stack. Useful for debugging. * {@link TemplateException}s incorporate this information in their stack * traces. */ public void outputInstructionStack(PrintWriter pw) { pw.println("----------"); ListIterator iter = elementStack.listIterator(elementStack.size()); if(iter.hasPrevious()) { pw.print("==> "); TemplateElement prev = (TemplateElement) iter.previous(); pw.print(prev.getDescription()); pw.print(" ["); pw.print(prev.getStartLocation()); pw.println("]"); } while(iter.hasPrevious()) { TemplateElement prev = (TemplateElement) iter.previous(); if (prev instanceof UnifiedCall || prev instanceof Include) { String location = prev.getDescription() + " [" + prev.getStartLocation() + "]"; if(location != null && location.length() > 0) { pw.print(" in "); pw.println(location); } } } pw.println("----------"); pw.flush(); } private void pushLocalContext(LocalContext localContext) { if (localContextStack == null) { localContextStack = new ArrayList(); } localContextStack.add(localContext); } private void popLocalContext() { localContextStack.remove(localContextStack.size() - 1); } ArrayList getLocalContextStack() { return localContextStack; } /** * Returns the name-space for the name if exists, or null. * @param name the template path that you have used with the import directive * or {@link #importLib(String, String)} call, in normalized form. That is, the path must be an absolute * path, and it must not contain "/../" or "/./". The leading "/" is optional. */ public Namespace getNamespace(String name) { if (name.startsWith("/")) name = name.substring(1); if (loadedLibs != null) { return (Namespace) loadedLibs.get(name); } else { return null; } } /** * Returns the main name-space. * This is correspondent of FTL .main hash. */ public Namespace getMainNamespace() { return mainNamespace; } /** * Returns the main name-space. * This is correspondent of FTL .namespace hash. */ public Namespace getCurrentNamespace() { return currentNamespace; } /** * Returns a fictitious name-space that contains the globally visible variables * that were created in the template, but not the variables of the data-model. * There is no such thing in FTL; this strange method was added because of the * JSP taglib support, since this imaginary name-space contains the page-scope * attributes. */ public Namespace getGlobalNamespace() { return globalNamespace; } public TemplateHashModel getDataModel() { final TemplateHashModel result = new TemplateHashModel() { public boolean isEmpty() { return false; } public TemplateModel get(String key) throws TemplateModelException { TemplateModel value = rootDataModel.get(key); if (value == null) { value = getConfiguration().getSharedVariable(key); } return value; } }; if (rootDataModel instanceof TemplateHashModelEx) { return new TemplateHashModelEx() { public boolean isEmpty() throws TemplateModelException { return result.isEmpty(); } public TemplateModel get(String key) throws TemplateModelException { return result.get(key); } //NB: The methods below do not take into account // configuration shared variables even though // the hash will return them, if only for BWC reasons public TemplateCollectionModel values() throws TemplateModelException { return ((TemplateHashModelEx) rootDataModel).values(); } public TemplateCollectionModel keys() throws TemplateModelException { return ((TemplateHashModelEx) rootDataModel).keys(); } public int size() throws TemplateModelException { return ((TemplateHashModelEx) rootDataModel).size(); } }; } return result; } /** * Returns the read-only hash of globally visible variables. * This is the correspondent of FTL .globals hash. * That is, you see the variables created with * <#global ...>, and the variables of the data-model. * To create new global variables, use {@link #setGlobalVariable setGlobalVariable}. */ public TemplateHashModel getGlobalVariables() { return new TemplateHashModel() { public boolean isEmpty() { return false; } public TemplateModel get(String key) throws TemplateModelException { TemplateModel result = globalNamespace.get(key); if (result == null) { result = rootDataModel.get(key); } if (result == null) { result = getConfiguration().getSharedVariable(key); } return result; } }; } private void pushElement(TemplateElement element) { elementStack.add(element); } private void popElement() { elementStack.remove(elementStack.size() - 1); } public TemplateNodeModel getCurrentVisitorNode() { return currentVisitorNode; } /** * sets TemplateNodeModel as the current visitor node. .current_node */ public void setCurrentVisitorNode(TemplateNodeModel node) { currentVisitorNode = node; } TemplateModel getNodeProcessor(TemplateNodeModel node) throws TemplateException { String nodeName = node.getNodeName(); if (nodeName == null) { throw new TemplateException("Node name is null.", this); } TemplateModel result = getNodeProcessor(nodeName, node.getNodeNamespace(), 0); if (result == null) { String type = node.getNodeType(); /* DD: Original version: */ if (type == null) { type = "default"; } result = getNodeProcessor("@" + type, null, 0); /* DD: Jonathan's non-BC version and IMHO otherwise wrong version: if (type != null) { result = getNodeProcessor("@" + type, null, 0); } if (result == null) { result = getNodeProcessor("@default", null, 0); } */ } return result; } private TemplateModel getNodeProcessor(final String nodeName, final String nsURI, int startIndex) throws TemplateException { TemplateModel result = null; int i; for (i = startIndex; i0) { result = ns.get(prefix + ":" + localName); if (!(result instanceof Macro) && !(result instanceof TemplateTransformModel)) { result = null; } } else { if (nsURI.length() == 0) { result = ns.get(Template.NO_NS_PREFIX + ":" + localName); if (!(result instanceof Macro) && !(result instanceof TemplateTransformModel)) { result = null; } } if (nsURI.equals(template.getDefaultNS())) { result = ns.get(Template.DEFAULT_NAMESPACE_PREFIX + ":" + localName); if (!(result instanceof Macro) && !(result instanceof TemplateTransformModel)) { result = null; } } if (result == null) { result = ns.get(localName); if (!(result instanceof Macro) && !(result instanceof TemplateTransformModel)) { result = null; } } } } return result; } /** * Emulates include directive, except that name must be tempate * root relative. * *

It's the same as include(getTemplateForInclusion(name, encoding, parse)). * But, you may want to separately call these two methods, so you can determine the source of * exceptions more precisely, and thus achieve more intelligent error handling. * * @see #getTemplateForInclusion(String name, String encoding, boolean parse) * @see #include(Template includedTemplate) */ public void include(String name, String encoding, boolean parse) throws IOException, TemplateException { include(getTemplateForInclusion(name, encoding, parse)); } /** * Gets a template for inclusion; used with {@link #include(Template includedTemplate)}. * The advantage over simply using config.getTemplate(...) is that it chooses * the default encoding as the include directive does. * * @param name the name of the template, relatively to the template root directory * (not the to the directory of the currently executing template file!). * (Note that you can use {@link freemarker.cache.TemplateCache#getFullTemplatePath} * to convert paths to template root relative paths.) * @param encoding the encoding of the obtained template. If null, * the encoding of the Template that is currently being processed in this * Environment is used. * @param parse whether to process a parsed template or just include the * unparsed template source. */ public Template getTemplateForInclusion(String name, String encoding, boolean parse) throws IOException { if (encoding == null) { encoding = getTemplate().getEncoding(); } if (encoding == null) { encoding = getConfiguration().getEncoding(this.getLocale()); } return getConfiguration().getTemplate(name, getLocale(), encoding, parse); } /** * Processes a Template in the context of this Environment, including its * output in the Environment's Writer. * * @param includedTemplate the template to process. Note that it does not need * to be a template returned by * {@link #getTemplateForInclusion(String name, String encoding, boolean parse)}. */ public void include(Template includedTemplate) throws TemplateException, IOException { Template prevTemplate = getTemplate(); setParent(includedTemplate); importMacros(includedTemplate); try { visit(includedTemplate.getRootTreeNode()); } finally { setParent(prevTemplate); } } /** * Emulates import directive, except that name must be tempate * root relative. * *

It's the same as importLib(getTemplateForImporting(name), namespace). * But, you may want to separately call these two methods, so you can determine the source of * exceptions more precisely, and thus achieve more intelligent error handling. * * @see #getTemplateForImporting(String name) * @see #importLib(Template includedTemplate, String namespace) */ public Namespace importLib(String name, String namespace) throws IOException, TemplateException { return importLib(getTemplateForImporting(name), namespace); } /** * Gets a template for importing; used with * {@link #importLib(Template importedTemplate, String namespace)}. The advantage * over simply using config.getTemplate(...) is that it chooses the encoding * as the import directive does. * * @param name the name of the template, relatively to the template root directory * (not the to the directory of the currently executing template file!). * (Note that you can use {@link freemarker.cache.TemplateCache#getFullTemplatePath} * to convert paths to template root relative paths.) */ public Template getTemplateForImporting(String name) throws IOException { return getTemplateForInclusion(name, null, true); } /** * Emulates import directive. * * @param loadedTemplate the template to import. Note that it does not need * to be a template returned by {@link #getTemplateForImporting(String name)}. */ public Namespace importLib(Template loadedTemplate, String namespace) throws IOException, TemplateException { if (loadedLibs == null) { loadedLibs = new HashMap(); } String templateName = loadedTemplate.getName(); Namespace existingNamespace = (Namespace) loadedLibs.get(templateName); if (existingNamespace != null) { if (namespace != null) { setVariable(namespace, existingNamespace); } } else { Namespace newNamespace = new Namespace(loadedTemplate); if (namespace != null) { currentNamespace.put(namespace, newNamespace); if (currentNamespace == mainNamespace) { globalNamespace.put(namespace, newNamespace); } } Namespace prevNamespace = this.currentNamespace; this.currentNamespace = newNamespace; loadedLibs.put(templateName, currentNamespace); Writer prevOut = out; this.out = NULL_WRITER; try { include(loadedTemplate); } finally { this.out = prevOut; this.currentNamespace = prevNamespace; } } return (Namespace) loadedLibs.get(templateName); } String renderElementToString(TemplateElement te) throws IOException, TemplateException { Writer prevOut = out; try { StringWriter sw = new StringWriter(); this.out = sw; visit(te); return sw.toString(); } finally { this.out = prevOut; } } void importMacros(Template template) { for (Iterator it = template.getMacros().values().iterator(); it.hasNext();) { visitMacroDef((Macro) it.next()); } } /** * @return the namespace URI registered for this prefix, or null. * This is based on the mappings registered in the current namespace. */ public String getNamespaceForPrefix(String prefix) { return currentNamespace.getTemplate().getNamespaceForPrefix(prefix); } public String getPrefixForNamespace(String nsURI) { return currentNamespace.getTemplate().getPrefixForNamespace(nsURI); } /** * @return the default node namespace for the current FTL namespace */ public String getDefaultNS() { return currentNamespace.getTemplate().getDefaultNS(); } /** * A hook that Jython uses. */ public Object __getitem__(String key) throws TemplateModelException { return BeansWrapper.getDefaultInstance().unwrap(getVariable(key)); } /** * A hook that Jython uses. */ public void __setitem__(String key, Object o) throws TemplateException { setGlobalVariable(key, getObjectWrapper().wrap(o)); } private static final class NumberFormatKey { private final String pattern; private final Locale locale; NumberFormatKey(String pattern, Locale locale) { this.pattern = pattern; this.locale = locale; } public boolean equals(Object o) { if(o instanceof NumberFormatKey) { NumberFormatKey fk = (NumberFormatKey)o; return fk.pattern.equals(pattern) && fk.locale.equals(locale); } return false; } public int hashCode() { return pattern.hashCode() ^ locale.hashCode(); } } private static final class DateFormatKey { private final int dateType; private final String pattern; private final Locale locale; private final TimeZone timeZone; DateFormatKey(int dateType, String pattern, Locale locale, TimeZone timeZone) { this.dateType = dateType; this.pattern = pattern; this.locale = locale; this.timeZone = timeZone; } public boolean equals(Object o) { if(o instanceof DateFormatKey) { DateFormatKey fk = (DateFormatKey)o; return dateType == fk.dateType && fk.pattern.equals(pattern) && fk.locale.equals(locale) && fk.timeZone.equals(timeZone); } return false; } public int hashCode() { return dateType ^ pattern.hashCode() ^ locale.hashCode() ^ timeZone.hashCode(); } } public class Namespace extends SimpleHash { private Template template; Namespace() { this.template = Environment.this.getTemplate(); } Namespace(Template template) { this.template = template; } /** * @return the Template object with which this Namespace is associated. */ public Template getTemplate() { return template == null ? Environment.this.getTemplate() : template; } } static final Writer NULL_WRITER = new Writer() { public void write(char cbuf[], int off, int len) {} public void flush() {} public void close() {} }; private static final Writer EMPTY_BODY_WRITER = new Writer() { public void write(char[] cbuf, int off, int len) throws IOException { if (len > 0) { throw new IOException( "This transform does not allow nested content."); } } public void flush() { } public void close() { } }; } libfreemarker-java-2.3.19.orig/src/freemarker/core/HashLiteral.java0000644000175000017500000001375211723544470024552 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import java.util.*; final class HashLiteral extends Expression { private final ArrayList keys, values; private final int size; HashLiteral(ArrayList keys, ArrayList values) { this.keys = keys; this.values = values; this.size = keys.size(); keys.trimToSize(); values.trimToSize(); } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return new SequenceHash(env); } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("{"); for (int i = 0; i < size; i++) { Expression key = (Expression) keys.get(i); Expression value = (Expression) values.get(i); buf.append(key.getCanonicalForm()); buf.append(" : "); buf.append(value.getCanonicalForm()); if (i != size-1) { buf.append(","); } } buf.append("}"); return buf.toString(); } boolean isLiteral() { if (constantValue != null) { return true; } for (int i = 0; i < size; i++) { Expression key = (Expression) keys.get(i); Expression value = (Expression) values.get(i); if (!key.isLiteral() || !value.isLiteral()) { return false; } } return true; } Expression _deepClone(String name, Expression subst) { ArrayList clonedKeys = (ArrayList)keys.clone(); for (ListIterator iter = clonedKeys.listIterator(); iter.hasNext();) { iter.set(((Expression)iter.next()).deepClone(name, subst)); } ArrayList clonedValues = (ArrayList)values.clone(); for (ListIterator iter = clonedValues.listIterator(); iter.hasNext();) { iter.set(((Expression)iter.next()).deepClone(name, subst)); } return new HashLiteral(clonedKeys, clonedValues); } private class SequenceHash implements TemplateHashModelEx { private HashMap keyMap; // maps keys to integer offset private TemplateCollectionModel keyCollection, valueCollection; // ordered lists of keys and values SequenceHash(Environment env) throws TemplateException { keyMap = new HashMap(); ArrayList keyList = new ArrayList(size); ArrayList valueList = new ArrayList(size); for (int i = 0; i< size; i++) { Expression keyExp = (Expression) keys.get(i); Expression valExp = (Expression) values.get(i); String key = keyExp.getStringValue(env); TemplateModel value = valExp.getAsTemplateModel(env); assertNonNull(value, valExp, env); keyMap.put(key, value); keyList.add(key); valueList.add(value); } keyCollection = new CollectionAndSequence(new SimpleSequence(keyList)); valueCollection = new CollectionAndSequence(new SimpleSequence(valueList)); } public int size() { return size; } public TemplateCollectionModel keys() { return keyCollection; } public TemplateCollectionModel values() { return valueCollection; } public TemplateModel get(String key) { return (TemplateModel) keyMap.get(key); } public boolean isEmpty() { return size == 0; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/SwitchBlock.java0000644000175000017500000001175411723544471024567 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.*; import java.io.IOException; import freemarker.template.*; /** * An instruction representing a switch-case structure. */ final class SwitchBlock extends TemplateElement { private Case defaultCase; private Expression testExpression; /** * @param testExpression the expression to be tested. */ SwitchBlock(Expression testExpression) { this.testExpression = testExpression; nestedElements = new LinkedList(); } /** * @param cas a Case element. */ void addCase(Case cas) { if (cas.isDefault) { defaultCase = cas; } nestedElements.add(cas); } void accept(Environment env) throws TemplateException, IOException { boolean processedCase = false; Iterator iterator = nestedElements.iterator(); try { while (iterator.hasNext()) { Case cas = (Case)iterator.next(); boolean processCase = false; // Fall through if a previous case tested true. if (processedCase) { processCase = true; } else if (!cas.isDefault) { // Otherwise, if this case isn't the default, test it. ComparisonExpression equalsOp = new ComparisonExpression(testExpression, cas.expression, "=="); processCase = equalsOp.isTrue(env); } if (processCase) { env.visit(cas); processedCase = true; } } // If we didn't process any nestedElements, and we have a default, // process it. if (!processedCase && defaultCase != null) { env.visit(defaultCase); } } catch (BreakInstruction.Break br) {} } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#switch "); buf.append(testExpression.getCanonicalForm()); buf.append(">"); for (int i = 0; i"); return buf.toString(); } public String getDescription() { return "switch " + testExpression; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/AttemptBlock.java0000644000175000017500000000715211723544470024740 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.util.ArrayList; import freemarker.template.*; final class AttemptBlock extends TemplateElement { private TemplateElement attemptBlock, recoveryBlock; AttemptBlock(TemplateElement attemptBlock, TemplateElement recoveryBlock) { this.attemptBlock = attemptBlock; this.recoveryBlock = recoveryBlock; nestedElements = new ArrayList(); nestedElements.add(attemptBlock); nestedElements.add(recoveryBlock); } void accept(Environment env) throws TemplateException, IOException { env.visit(attemptBlock, recoveryBlock); } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#attempt>"); if (attemptBlock != null) { buf.append(attemptBlock.getCanonicalForm()); } if (recoveryBlock != null) { buf.append(recoveryBlock.getCanonicalForm()); } return buf.toString(); } public String getDescription() { return "attempt block"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ExistsExpression.java0000644000175000017500000000662211723544471025710 0ustar ebourgebourg/* * Copyright (c) 2006 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; class ExistsExpression extends Expression { private Expression exp; ExistsExpression(Expression exp) { this.exp = exp; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = null; try { tm = exp.getAsTemplateModel(env); } catch (InvalidReferenceException ire) { if (!(exp instanceof ParentheticalExpression)) { throw ire; } } return tm == null ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE; } boolean isLiteral() { return false; } Expression _deepClone(String name, Expression subst) { return new ExistsExpression(exp.deepClone(name, subst)); } public String getCanonicalForm() { return exp.getCanonicalForm() + "??"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TemplateElement.java0000644000175000017500000003004411723544470025430 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.*; import java.io.IOException; import javax.swing.tree.TreeNode; import freemarker.template.*; import freemarker.template.utility.Collections12; /** * Objects that represent elements in the compiled * tree representation of the template necessarily * descend from this abstract class. */ abstract public class TemplateElement extends TemplateObject implements TreeNode { TemplateElement parent; // Only one of nestedBlock and nestedElements can be non-null. TemplateElement nestedBlock; List nestedElements; /** * Processes the contents of this TemplateElement and * outputs the resulting text * * @param env The runtime environment */ abstract void accept(Environment env) throws TemplateException, IOException; abstract public String getDescription(); // Methods to implement TemplateNodeModel public TemplateNodeModel getParentNode() { // return parent; return null; } public String getNodeNamespace() { return null; } public String getNodeType() { return "element"; } public TemplateSequenceModel getChildNodes() { if (nestedElements != null) { return new SimpleSequence(nestedElements); } SimpleSequence result = new SimpleSequence(); if (nestedBlock != null) { result.add(nestedBlock); } return result; } public String getNodeName() { String classname = this.getClass().getName(); int shortNameOffset = classname.lastIndexOf('.')+1; return classname.substring(shortNameOffset); } // Methods so that we can implement the Swing TreeNode API. public boolean isLeaf() { return nestedBlock == null && (nestedElements == null || nestedElements.isEmpty()); } public boolean getAllowsChildren() { return !isLeaf(); } public int getIndex(TreeNode node) { if (nestedBlock instanceof MixedContent) { return nestedBlock.getIndex(node); } if (nestedBlock != null) { if (node == nestedBlock) { return 0; } } else if (nestedElements != null) { return nestedElements.indexOf(node); } return -1; } public int getChildCount() { if (nestedBlock instanceof MixedContent) { return nestedBlock.getChildCount(); } if (nestedBlock != null) { return 1; } else if (nestedElements != null) { return nestedElements.size(); } return 0; } public Enumeration children() { if (nestedBlock instanceof MixedContent) { return nestedBlock.children(); } if (nestedBlock != null) { return Collections.enumeration(Collections12.singletonList(nestedBlock)); } else if (nestedElements != null) { return Collections.enumeration(nestedElements); } return Collections.enumeration(Collections.EMPTY_LIST); } public TreeNode getChildAt(int index) { if (nestedBlock instanceof MixedContent) { return nestedBlock.getChildAt(index); } if (nestedBlock != null) { if (index == 0) { return nestedBlock; } throw new ArrayIndexOutOfBoundsException("invalid index"); } else if (nestedElements != null) { return(TreeNode) nestedElements.get(index); } throw new ArrayIndexOutOfBoundsException("element has no children"); } public void setChildAt(int index, TemplateElement element) { if(nestedBlock instanceof MixedContent) { nestedBlock.setChildAt(index, element); } else if(nestedBlock != null) { if(index == 0) { nestedBlock = element; element.parent = this; } else { throw new IndexOutOfBoundsException("invalid index"); } } else if(nestedElements != null) { nestedElements.set(index, element); element.parent = this; } else { throw new IndexOutOfBoundsException("element has no children"); } } public TreeNode getParent() { return parent; } // Walk the tree and set the parent field in all the nested elements recursively. void setParentRecursively(TemplateElement parent) { this.parent = parent; int nestedSize = nestedElements == null ? 0 : nestedElements.size(); for (int i = 0; i < nestedSize; i++) { ((TemplateElement) nestedElements.get(i)).setParentRecursively(this); } if (nestedBlock != null) { nestedBlock.setParentRecursively(this); } } /** * We walk the tree and do some cleanup * @param stripWhitespace whether to clean up superfluous whitespace */ TemplateElement postParseCleanup(boolean stripWhitespace) throws ParseException { if (nestedElements != null) { for (int i = 0; i < nestedElements.size(); i++) { TemplateElement te = (TemplateElement) nestedElements.get(i); te = te.postParseCleanup(stripWhitespace); nestedElements.set(i, te); te.parent = this; } if (stripWhitespace) { for (Iterator it = nestedElements.iterator(); it.hasNext();) { TemplateElement te = (TemplateElement) it.next(); if (te.isIgnorable()) { it.remove(); } } } if (nestedElements instanceof ArrayList) { ((ArrayList) nestedElements).trimToSize(); } } if (nestedBlock != null) { nestedBlock = nestedBlock.postParseCleanup(stripWhitespace); if (nestedBlock.isIgnorable()) { nestedBlock = null; } else { nestedBlock.parent = this; } } return this; } boolean isIgnorable() { return false; } // The following methods exist to support some fancier tree-walking // and were introduced to support the whitespace cleanup feature in 2.2 TemplateElement prevTerminalNode() { TemplateElement prev = previousSibling(); if (prev != null) { return prev.getLastLeaf(); } else if (parent != null) { return parent.prevTerminalNode(); } return null; } TemplateElement nextTerminalNode() { TemplateElement next = nextSibling(); if (next != null) { return next.getFirstLeaf(); } else if (parent != null) { return parent.nextTerminalNode(); } return null; } TemplateElement previousSibling() { if (parent == null) { return null; } List siblings = parent.nestedElements; if (siblings == null) { return null; } for (int i = siblings.size() - 1; i>=0; i--) { if (siblings.get(i) == this) { return(i >0) ? (TemplateElement) siblings.get(i-1) : null; } } return null; } TemplateElement nextSibling() { if (parent == null) { return null; } List siblings = parent.nestedElements; if (siblings == null) { return null; } for (int i = 0; i < siblings.size(); i++) { if (siblings.get(i) == this) { return (i+1) < siblings.size() ? (TemplateElement) siblings.get(i+1) : null; } } return null; } private TemplateElement getFirstChild() { if (nestedBlock != null) { return nestedBlock; } if (nestedElements != null && nestedElements.size() >0) { return(TemplateElement) nestedElements.get(0); } return null; } private TemplateElement getLastChild() { if (nestedBlock != null) { return nestedBlock; } if (nestedElements != null && nestedElements.size() >0) { return(TemplateElement) nestedElements.get(nestedElements.size() -1); } return null; } private TemplateElement getFirstLeaf() { TemplateElement te = this; while (!te.isLeaf() && !(te instanceof Macro) && !(te instanceof BlockAssignment)) { // A macro or macro invocation is treated as a leaf here for special reasons te = te.getFirstChild(); } return te; } private TemplateElement getLastLeaf() { TemplateElement te = this; while (!te.isLeaf() && !(te instanceof Macro) && !(te instanceof BlockAssignment)) { // A macro or macro invocation is treated as a leaf here for special reasons te = te.getLastChild(); } return te; } /** * determines whether this element's presence on a line * indicates that we should not strip opening whitespace * in the post-parse whitespace gobbling step. */ boolean heedsOpeningWhitespace() { return false; } /** * determines whether this element's presence on a line * indicates that we should not strip trailing whitespace * in the post-parse whitespace gobbling step. */ boolean heedsTrailingWhitespace() { return false; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/OrExpression.java0000644000175000017500000000654211723544471025012 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; final class OrExpression extends BooleanExpression { private final Expression left; private final Expression right; OrExpression(Expression left, Expression right) { this.left = left; this.right = right; } boolean isTrue(Environment env) throws TemplateException { return left.isTrue(env) || right.isTrue(env); } public String getCanonicalForm() { return left.getCanonicalForm() + " || " + right.getCanonicalForm(); } boolean isLiteral() { return constantValue !=null || (left.isLiteral() && right.isLiteral()); } Expression _deepClone(String name, Expression subst) { return new OrExpression(left.deepClone(name, subst), right.deepClone(name, subst)); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NumericalOutput.java0000644000175000017500000001331611723544471025507 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.text.NumberFormat; import java.util.Locale; import freemarker.template.*; /** * An instruction that outputs the value of a numerical expression. * @author Jonathan Revusky */ final class NumericalOutput extends TemplateElement { private final Expression expression; private final boolean hasFormat; private final int minFracDigits; private final int maxFracDigits; private volatile FormatHolder formatCache; // creating new NumberFormat is slow operation NumericalOutput(Expression expression) { this.expression = expression; hasFormat = false; this.minFracDigits = 0; this.maxFracDigits = 0; } NumericalOutput(Expression expression, int minFracDigits, int maxFracDigits) { this.expression = expression; hasFormat = true; this.minFracDigits = minFracDigits; this.maxFracDigits = maxFracDigits; } void accept(Environment env) throws TemplateException, IOException { Number num = EvaluationUtil.getNumber(expression, env); FormatHolder fmth = formatCache; // atomic sampling if (fmth == null || !fmth.locale.equals(env.getLocale())) { synchronized(this) { fmth = formatCache; if (fmth == null || !fmth.locale.equals(env.getLocale())) { NumberFormat fmt = NumberFormat.getNumberInstance(env.getLocale()); if (hasFormat) { fmt.setMinimumFractionDigits(minFracDigits); fmt.setMaximumFractionDigits(maxFracDigits); } else { fmt.setMinimumFractionDigits(0); fmt.setMaximumFractionDigits(50); } fmt.setGroupingUsed(false); formatCache = new FormatHolder(fmt, env.getLocale()); fmth = formatCache; } } } // We must use Format even if hasFormat == false. // Some locales may use non-Arabic digits, thus replacing the // decimal separator in the result of toString() is not enough. env.getOut().write(fmth.format.format(num)); } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("#{"); buf.append(expression.getCanonicalForm()); if (hasFormat) { buf.append(" ; "); buf.append("m"); buf.append(minFracDigits); buf.append("M"); buf.append(maxFracDigits); } buf.append("}"); return buf.toString(); } public String getDescription() { return getSource(); } boolean heedsOpeningWhitespace() { return true; } boolean heedsTrailingWhitespace() { return true; } private static class FormatHolder { final NumberFormat format; final Locale locale; FormatHolder(NumberFormat format, Locale locale) { this.format = format; this.locale = locale; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/DefaultToExpression.java0000644000175000017500000001072511723544471026317 0ustar ebourgebourg/* * Copyright (c) 2006 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; class DefaultToExpression extends Expression { private static final TemplateCollectionModel EMPTY_COLLECTION = new SimpleCollection(new java.util.ArrayList(0)); static private class EmptyStringAndSequence implements TemplateScalarModel, TemplateSequenceModel, TemplateHashModelEx { public String getAsString() { return ""; } public TemplateModel get(int i) { return null; } public TemplateModel get(String s) { return null; } public int size() { return 0; } public boolean isEmpty() { return true; } public TemplateCollectionModel keys() { return EMPTY_COLLECTION; } public TemplateCollectionModel values() { return EMPTY_COLLECTION; } } static final TemplateModel EMPTY_STRING_AND_SEQUENCE = new EmptyStringAndSequence(); private Expression lhs, rhs; DefaultToExpression(Expression lhs, Expression rhs) { this.lhs = lhs; this.rhs = rhs; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel left = null; try { left = lhs.getAsTemplateModel(env); } catch (InvalidReferenceException ire) { if (!(lhs instanceof ParentheticalExpression)) { throw ire; } } if (left != null) return left; if (rhs == null) return EMPTY_STRING_AND_SEQUENCE; return rhs.getAsTemplateModel(env); } boolean isLiteral() { return false; } Expression _deepClone(String name, Expression subst) { if (rhs == null) { return new DefaultToExpression(lhs.deepClone(name, subst), null); } return new DefaultToExpression(lhs.deepClone(name, subst), rhs.deepClone(name, subst)); } public String getCanonicalForm() { if (rhs == null) { return lhs.getCanonicalForm() + "!"; } return lhs.getCanonicalForm() + "!" + rhs.getCanonicalForm(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/UnaryPlusMinusExpression.java0000644000175000017500000000767411723544471027417 0ustar ebourgebourg/* * Copyright (c) 2005 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; final class UnaryPlusMinusExpression extends Expression { private final Expression target; private final boolean isMinus; private static final Integer MINUS_ONE = new Integer(-1); UnaryPlusMinusExpression(Expression target, boolean isMinus) { this.target = target; this.isMinus = isMinus; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateNumberModel targetModel = null; try { targetModel = (TemplateNumberModel) target.getAsTemplateModel(env); } catch (ClassCastException cce) { String msg = "Error " + getStartLocation(); msg += "\nExpression " + target + " is not numerical."; throw new NonNumericalException(msg, env); } if (!isMinus) { return targetModel; } Number n = targetModel.getAsNumber(); n = ArithmeticEngine.CONSERVATIVE_ENGINE.multiply(MINUS_ONE, n); return new SimpleNumber(n); } public String getCanonicalForm() { String op = isMinus ? "-" : "+"; return op + target.getCanonicalForm(); } boolean isLiteral() { return target.isLiteral(); } Expression _deepClone(String name, Expression subst) { return new UnaryPlusMinusExpression(target.deepClone(name, subst), isMinus); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/StringBuiltins.java0000644000175000017500000002117211723544471025326 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import freemarker.template.utility.StringUtil; import java.io.StringReader; import java.util.StringTokenizer; /** * A holder for builtins that operate exclusively on strings. */ abstract class StringBuiltins { abstract static class StringBuiltIn extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return calculateResult(target.getStringValue(env), env); } abstract TemplateModel calculateResult(String s, Environment env) throws TemplateException; } static class capitalizeBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.capitalize(s)); } } static class chop_linebreakBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.chomp(s)); } } static class j_stringBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.javaStringEnc(s)); } } static class js_stringBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.javaScriptStringEnc(s)); } } static class json_stringBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.jsonStringEnc(s)); } } static class cap_firstBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { int i = 0; int ln = s.length(); while (i < ln && Character.isWhitespace(s.charAt(i))) { i++; } if (i < ln) { StringBuffer b = new StringBuffer(s); b.setCharAt(i, Character.toUpperCase(s.charAt(i))); s = b.toString(); } return new SimpleScalar(s); } } static class uncap_firstBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { int i = 0; int ln = s.length(); while (i < ln && Character.isWhitespace(s.charAt(i))) { i++; } if (i < ln) { StringBuffer b = new StringBuffer(s); b.setCharAt(i, Character.toLowerCase(s.charAt(i))); s = b.toString(); } return new SimpleScalar(s); } } static class upper_caseBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(s.toUpperCase(env.getLocale())); } } static class lower_caseBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(s.toLowerCase(env.getLocale())); } } static class word_listBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { SimpleSequence result = new SimpleSequence(); StringTokenizer st = new StringTokenizer(s); while (st.hasMoreTokens()) { result.add(st.nextToken()); } return result; } } static class evalBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) throws TemplateException { SimpleCharStream scs = new SimpleCharStream( new StringReader("(" + s + ")"), target.beginLine, target.beginColumn, s.length() + 2); FMParserTokenManager token_source = new FMParserTokenManager(scs); token_source.incompatibleChanges = env.getConfiguration().getParsedIncompatibleEnhancements(); token_source.SwitchTo(FMParserConstants.FM_EXPRESSION); FMParser parser = new FMParser(token_source); parser.template = getTemplate(); Expression exp = null; try { exp = parser.Expression(); } catch (ParseException pe) { pe.setTemplateName(getTemplate().getName()); throw new TemplateException(pe, env); } return exp.getAsTemplateModel(env); } } static class numberBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) throws TemplateException { try { return new SimpleNumber(env.getArithmeticEngine().toNumber(s)); } catch(NumberFormatException nfe) { String mess = "Error: " + getStartLocation() + "\nExpecting a number here, found: " + s; throw new NonNumericalException(mess, env); } } } static class substringBI extends StringBuiltIn { TemplateModel calculateResult(final String s, final Environment env) throws TemplateException { return new TemplateMethodModelEx() { public Object exec(java.util.List args) throws TemplateModelException { int argCount = args.size(), left=0, right=0; if (argCount != 1 && argCount != 2) { throw new TemplateModelException("Error: " + getStartLocation() + "\nExpecting 1 or 2 numerical arguments here"); } try { TemplateNumberModel tnm = (TemplateNumberModel) args.get(0); left = tnm.getAsNumber().intValue(); if (argCount == 2) { tnm = (TemplateNumberModel) args.get(1); right = tnm.getAsNumber().intValue(); } } catch (ClassCastException cce) { String mess = "Error: " + getStartLocation() + "\nExpecting numerical argument here"; throw new TemplateModelException(mess); } if (argCount == 1) { return new SimpleScalar(s.substring(left)); } return new SimpleScalar(s.substring(left, right)); } }; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FreeMarkerTree.java0000644000175000017500000000650511723544471025214 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import javax.swing.JTree; import javax.swing.tree.DefaultTreeModel; abstract public class FreeMarkerTree extends JTree { public FreeMarkerTree(Template template) { super(template.getRootTreeNode()); } public void setTemplate(Template template) { this.setModel(new DefaultTreeModel(template.getRootTreeNode())); this.invalidate(); } public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { if (value instanceof TemplateElement) { return ((TemplateElement) value).getDescription(); } return value.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/DollarVariable.java0000644000175000017500000000726411723544470025236 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.TemplateException; /** * An instruction that outputs the value of an Expression. */ final class DollarVariable extends TemplateElement { private final Expression expression; private final Expression escapedExpression; DollarVariable(Expression expression, Expression escapedExpression) { this.expression = expression; this.escapedExpression = escapedExpression; } /** * Outputs the string value of the enclosed expression. */ void accept(Environment env) throws TemplateException, IOException { env.getOut().write(escapedExpression.getStringValue(env)); } public String getCanonicalForm() { return "${" + expression.getCanonicalForm() + "}"; } public String getDescription() { return this.getSource() + (expression == escapedExpression ? "" : " escaped ${" + escapedExpression.getCanonicalForm() + "}"); } boolean heedsOpeningWhitespace() { return true; } boolean heedsTrailingWhitespace() { return true; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ArithmeticEngine.java0000644000175000017500000005407211723544467025577 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.math.*; import java.util.HashMap; import java.util.Map; import freemarker.template.*; import freemarker.template.utility.OptimizerUtil; /** * Class to perform arithmetic operations. * @author Jonathan Revusky * @author Attila Szegedi */ public abstract class ArithmeticEngine { /** * Arithmetic engine that converts all numbers to {@link BigDecimal} and * then operates on them. This is FreeMarker's default arithmetic engine. */ public static final BigDecimalEngine BIGDECIMAL_ENGINE = new BigDecimalEngine(); /** * Arithmetic engine that uses (more-or-less) the widening conversions of * Java language to determine the type of result of operation, instead of * converting everything to BigDecimal up front. */ public static final ConservativeEngine CONSERVATIVE_ENGINE = new ConservativeEngine(); public abstract int compareNumbers(Number first, Number second) throws TemplateException; public abstract Number add(Number first, Number second) throws TemplateException; public abstract Number subtract(Number first, Number second) throws TemplateException; public abstract Number multiply(Number first, Number second) throws TemplateException; public abstract Number divide(Number first, Number second) throws TemplateException; public abstract Number modulus(Number first, Number second) throws TemplateException; public abstract Number toNumber(String s); protected int minScale = 12; protected int maxScale = 12; protected int roundingPolicy = BigDecimal.ROUND_HALF_UP; /** * Sets the minimal scale to use when dividing BigDecimal numbers. Default * value is 12. */ public void setMinScale(int minScale) { if(minScale < 0) { throw new IllegalArgumentException("minScale < 0"); } this.minScale = minScale; } /** * Sets the maximal scale to use when multiplying BigDecimal numbers. * Default value is 100. */ public void setMaxScale(int maxScale) { if(maxScale < minScale) { throw new IllegalArgumentException("maxScale < minScale"); } this.maxScale = maxScale; } public void setRoundingPolicy(int roundingPolicy) { if (roundingPolicy != BigDecimal.ROUND_CEILING && roundingPolicy != BigDecimal.ROUND_DOWN && roundingPolicy != BigDecimal.ROUND_FLOOR && roundingPolicy != BigDecimal.ROUND_HALF_DOWN && roundingPolicy != BigDecimal.ROUND_HALF_EVEN && roundingPolicy != BigDecimal.ROUND_HALF_UP && roundingPolicy != BigDecimal.ROUND_UNNECESSARY && roundingPolicy != BigDecimal.ROUND_UP) { throw new IllegalArgumentException("invalid rounding policy"); } this.roundingPolicy = roundingPolicy; } /** * This is the default arithmetic engine in FreeMarker. It converts every * number it receives into {@link BigDecimal}, then operates on these * converted {@link BigDecimal}s. */ public static class BigDecimalEngine extends ArithmeticEngine { public int compareNumbers(Number first, Number second) { BigDecimal left = toBigDecimal(first); BigDecimal right = toBigDecimal(second); return left.compareTo(right); } public Number add(Number first, Number second) { BigDecimal left = toBigDecimal(first); BigDecimal right = toBigDecimal(second); return left.add(right); } public Number subtract(Number first, Number second) { BigDecimal left = toBigDecimal(first); BigDecimal right = toBigDecimal(second); return left.subtract(right); } public Number multiply(Number first, Number second) { BigDecimal left = toBigDecimal(first); BigDecimal right = toBigDecimal(second); BigDecimal result = left.multiply(right); if (result.scale() > maxScale) { result = result.setScale(maxScale, roundingPolicy); } return result; } public Number divide(Number first, Number second) { BigDecimal left = toBigDecimal(first); BigDecimal right = toBigDecimal(second); return divide(left, right); } public Number modulus(Number first, Number second) { long left = first.longValue(); long right = second.longValue(); return new Long(left % right); } public Number toNumber(String s) { return new BigDecimal(s); } private BigDecimal divide(BigDecimal left, BigDecimal right) { int scale1 = left.scale(); int scale2 = right.scale(); int scale = Math.max(scale1, scale2); scale = Math.max(minScale, scale); return left.divide(right, scale, roundingPolicy); } } /** * An arithmetic engine that conservatively widens the operation arguments * to extent that they can hold the result of the operation. Widening * conversions occur in following situations: *

    *
  • byte and short are always widened to int (alike to Java language).
  • *
  • To preserve magnitude: when operands are of different types, the * result type is the type of the wider operand.
  • *
  • to avoid overflows: if add, subtract, or multiply would overflow on * integer types, the result is widened from int to long, or from long to * BigInteger.
  • *
  • to preserve fractional part: if a division of integer types would * have a fractional part, int and long are converted to double, and * BigInteger is converted to BigDecimal. An operation on a float and a * long results in a double. An operation on a float or double and a * BigInteger results in a BigDecimal.
  • *
*/ public static class ConservativeEngine extends ArithmeticEngine { private static final int INTEGER = 0; private static final int LONG = 1; private static final int FLOAT = 2; private static final int DOUBLE = 3; private static final int BIGINTEGER = 4; private static final int BIGDECIMAL = 5; private static final Map classCodes = createClassCodesMap(); public int compareNumbers(Number first, Number second) throws TemplateException { switch(getCommonClassCode(first, second)) { case INTEGER: { int n1 = first.intValue(); int n2 = second.intValue(); return n1 < n2 ? -1 : (n1 == n2 ? 0 : 1); } case LONG: { long n1 = first.longValue(); long n2 = second.longValue(); return n1 < n2 ? -1 : (n1 == n2 ? 0 : 1); } case FLOAT: { float n1 = first.floatValue(); float n2 = second.floatValue(); return n1 < n2 ? -1 : (n1 == n2 ? 0 : 1); } case DOUBLE: { double n1 = first.doubleValue(); double n2 = second.doubleValue(); return n1 < n2 ? -1 : (n1 == n2 ? 0 : 1); } case BIGINTEGER: { BigInteger n1 = toBigInteger(first); BigInteger n2 = toBigInteger(second); return n1.compareTo(n2); } case BIGDECIMAL: { BigDecimal n1 = toBigDecimal(first); BigDecimal n2 = toBigDecimal(second); return n1.compareTo(n2); } } // Make the compiler happy. getCommonClassCode() is guaranteed to // return only above codes, or throw an exception. throw new Error(); } public Number add(Number first, Number second) throws TemplateException { switch(getCommonClassCode(first, second)) { case INTEGER: { int n1 = first.intValue(); int n2 = second.intValue(); int n = n1 + n2; return ((n ^ n1) < 0 && (n ^ n2) < 0) // overflow check ? (Number)new Long(((long)n1) + n2) : (Number)new Integer(n); } case LONG: { long n1 = first.longValue(); long n2 = second.longValue(); long n = n1 + n2; return ((n ^ n1) < 0 && (n ^ n2) < 0) // overflow check ? (Number)toBigInteger(first).add(toBigInteger(second)) : (Number)new Long(n); } case FLOAT: { return new Float(first.floatValue() + second.floatValue()); } case DOUBLE: { return new Double(first.doubleValue() + second.doubleValue()); } case BIGINTEGER: { BigInteger n1 = toBigInteger(first); BigInteger n2 = toBigInteger(second); return n1.add(n2); } case BIGDECIMAL: { BigDecimal n1 = toBigDecimal(first); BigDecimal n2 = toBigDecimal(second); return n1.add(n2); } } // Make the compiler happy. getCommonClassCode() is guaranteed to // return only above codes, or throw an exception. throw new Error(); } public Number subtract(Number first, Number second) throws TemplateException { switch(getCommonClassCode(first, second)) { case INTEGER: { int n1 = first.intValue(); int n2 = second.intValue(); int n = n1 - n2; return ((n ^ n1) < 0 && (n ^ ~n2) < 0) // overflow check ? (Number)new Long(((long)n1) - n2) : (Number)new Integer(n); } case LONG: { long n1 = first.longValue(); long n2 = second.longValue(); long n = n1 - n2; return ((n ^ n1) < 0 && (n ^ ~n2) < 0) // overflow check ? (Number)toBigInteger(first).subtract(toBigInteger(second)) : (Number)new Long(n); } case FLOAT: { return new Float(first.floatValue() - second.floatValue()); } case DOUBLE: { return new Double(first.doubleValue() - second.doubleValue()); } case BIGINTEGER: { BigInteger n1 = toBigInteger(first); BigInteger n2 = toBigInteger(second); return n1.subtract(n2); } case BIGDECIMAL: { BigDecimal n1 = toBigDecimal(first); BigDecimal n2 = toBigDecimal(second); return n1.subtract(n2); } } // Make the compiler happy. getCommonClassCode() is guaranteed to // return only above codes, or throw an exception. throw new Error(); } public Number multiply(Number first, Number second) throws TemplateException { switch(getCommonClassCode(first, second)) { case INTEGER: { int n1 = first.intValue(); int n2 = second.intValue(); int n = n1 * n2; return n1== 0 || n/n1 == n2 // overflow check ? (Number)new Integer(n) : (Number)new Long(((long)n1) * n2); } case LONG: { long n1 = first.longValue(); long n2 = second.longValue(); long n = n1 * n2; return n1==0L || n / n1 == n2 // overflow check ? (Number)new Long(n) : (Number)toBigInteger(first).multiply(toBigInteger(second)); } case FLOAT: { return new Float(first.floatValue() * second.floatValue()); } case DOUBLE: { return new Double(first.doubleValue() * second.doubleValue()); } case BIGINTEGER: { BigInteger n1 = toBigInteger(first); BigInteger n2 = toBigInteger(second); return n1.multiply(n2); } case BIGDECIMAL: { BigDecimal n1 = toBigDecimal(first); BigDecimal n2 = toBigDecimal(second); BigDecimal r = n1.multiply(n2); return r.scale() > maxScale ? r.setScale(maxScale, roundingPolicy) : r; } } // Make the compiler happy. getCommonClassCode() is guaranteed to // return only above codes, or throw an exception. throw new Error(); } public Number divide(Number first, Number second) throws TemplateException { switch(getCommonClassCode(first, second)) { case INTEGER: { int n1 = first.intValue(); int n2 = second.intValue(); if (n1 % n2 == 0) { return new Integer(n1/n2); } return new Double(((double)n1)/n2); } case LONG: { long n1 = first.longValue(); long n2 = second.longValue(); if (n1 % n2 == 0) { return new Long(n1/n2); } return new Double(((double)n1)/n2); } case FLOAT: { return new Float(first.floatValue() / second.floatValue()); } case DOUBLE: { return new Double(first.doubleValue() / second.doubleValue()); } case BIGINTEGER: { BigInteger n1 = toBigInteger(first); BigInteger n2 = toBigInteger(second); BigInteger[] divmod = n1.divideAndRemainder(n2); if(divmod[1].equals(BigInteger.ZERO)) { return divmod[0]; } else { BigDecimal bd1 = new BigDecimal(n1); BigDecimal bd2 = new BigDecimal(n2); return bd1.divide(bd2, minScale, roundingPolicy); } } case BIGDECIMAL: { BigDecimal n1 = toBigDecimal(first); BigDecimal n2 = toBigDecimal(second); int scale1 = n1.scale(); int scale2 = n2.scale(); int scale = Math.max(scale1, scale2); scale = Math.max(minScale, scale); return n1.divide(n2, scale, roundingPolicy); } } // Make the compiler happy. getCommonClassCode() is guaranteed to // return only above codes, or throw an exception. throw new Error(); } public Number modulus(Number first, Number second) throws TemplateException { switch(getCommonClassCode(first, second)) { case INTEGER: { return new Integer(first.intValue() % second.intValue()); } case LONG: { return new Long(first.longValue() % second.longValue()); } case FLOAT: { return new Float(first.floatValue() % second.floatValue()); } case DOUBLE: { return new Double(first.doubleValue() % second.doubleValue()); } case BIGINTEGER: { BigInteger n1 = toBigInteger(first); BigInteger n2 = toBigInteger(second); return n1.mod(n2); } case BIGDECIMAL: { throw new TemplateException("Can't calculate remainder on BigDecimals", Environment.getCurrentEnvironment()); } } // Make the compiler happy. getCommonClassCode() is guaranteed to // return only above codes, or throw an exception. throw new Error(); } public Number toNumber(String s) { return OptimizerUtil.optimizeNumberRepresentation(new BigDecimal(s)); } private static Map createClassCodesMap() { Map map = new HashMap(17); Integer intcode = new Integer(INTEGER); map.put(Byte.class, intcode); map.put(Short.class, intcode); map.put(Integer.class, intcode); map.put(Long.class, new Integer(LONG)); map.put(Float.class, new Integer(FLOAT)); map.put(Double.class, new Integer(DOUBLE)); map.put(BigInteger.class, new Integer(BIGINTEGER)); map.put(BigDecimal.class, new Integer(BIGDECIMAL)); return map; } private static int getClassCode(Number num) throws TemplateException { try { return ((Integer)classCodes.get(num.getClass())).intValue(); } catch(NullPointerException e) { if(num == null) { throw new TemplateException("Unknown number type null", Environment.getCurrentEnvironment()); } throw new TemplateException("Unknown number type " + num.getClass().getName(), Environment.getCurrentEnvironment()); } } private static int getCommonClassCode(Number num1, Number num2) throws TemplateException { int c1 = getClassCode(num1); int c2 = getClassCode(num2); int c = c1 > c2 ? c1 : c2; // If BigInteger is combined with a Float or Double, the result is a // BigDecimal instead of BigInteger in order not to lose the // fractional parts. If Float is combined with Long, the result is a // Double instead of Float to preserve the bigger bit width. switch(c) { case FLOAT: { if((c1 < c2 ? c1 : c2) == LONG) { return DOUBLE; } break; } case BIGINTEGER: { int min = c1 < c2 ? c1 : c2; if(min == DOUBLE || min == FLOAT) { return BIGDECIMAL; } break; } } return c; } private static BigInteger toBigInteger(Number num) { return num instanceof BigInteger ? (BigInteger) num : new BigInteger(num.toString()); } } private static BigDecimal toBigDecimal(Number num) { return num instanceof BigDecimal ? (BigDecimal) num : new BigDecimal(num.toString()); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FMParserConstants.java0000644000175000017500000001320511723544470025717 0ustar ebourgebourg/* Generated By:JavaCC: Do not edit this line. FMParserConstants.java */ package freemarker.core; interface FMParserConstants { int EOF = 0; int BLANK = 1; int START_TAG = 2; int END_TAG = 3; int CLOSE_TAG1 = 4; int CLOSE_TAG2 = 5; int ATTEMPT = 6; int RECOVER = 7; int IF = 8; int ELSE_IF = 9; int LIST = 10; int FOREACH = 11; int SWITCH = 12; int CASE = 13; int ASSIGN = 14; int GLOBALASSIGN = 15; int LOCALASSIGN = 16; int _INCLUDE = 17; int IMPORT = 18; int FUNCTION = 19; int MACRO = 20; int TRANSFORM = 21; int VISIT = 22; int STOP = 23; int RETURN = 24; int CALL = 25; int SETTING = 26; int COMPRESS = 27; int COMMENT = 28; int TERSE_COMMENT = 29; int NOPARSE = 30; int END_IF = 31; int END_LIST = 32; int END_RECOVER = 33; int END_ATTEMPT = 34; int END_FOREACH = 35; int END_LOCAL = 36; int END_GLOBAL = 37; int END_ASSIGN = 38; int END_FUNCTION = 39; int END_MACRO = 40; int END_COMPRESS = 41; int END_TRANSFORM = 42; int END_SWITCH = 43; int ELSE = 44; int BREAK = 45; int SIMPLE_RETURN = 46; int HALT = 47; int FLUSH = 48; int TRIM = 49; int LTRIM = 50; int RTRIM = 51; int NOTRIM = 52; int DEFAUL = 53; int SIMPLE_NESTED = 54; int NESTED = 55; int SIMPLE_RECURSE = 56; int RECURSE = 57; int FALLBACK = 58; int ESCAPE = 59; int END_ESCAPE = 60; int NOESCAPE = 61; int END_NOESCAPE = 62; int UNIFIED_CALL = 63; int UNIFIED_CALL_END = 64; int FTL_HEADER = 65; int TRIVIAL_FTL_HEADER = 66; int UNKNOWN_DIRECTIVE = 67; int WHITESPACE = 68; int PRINTABLE_CHARS = 69; int FALSE_ALERT = 70; int OUTPUT_ESCAPE = 71; int NUMERICAL_ESCAPE = 72; int ESCAPED_CHAR = 80; int STRING_LITERAL = 81; int RAW_STRING = 82; int FALSE = 83; int TRUE = 84; int INTEGER = 85; int DECIMAL = 86; int DOT = 87; int DOT_DOT = 88; int BUILT_IN = 89; int EXISTS = 90; int EQUALS = 91; int DOUBLE_EQUALS = 92; int NOT_EQUALS = 93; int LESS_THAN = 94; int LESS_THAN_EQUALS = 95; int ESCAPED_GT = 96; int ESCAPED_GTE = 97; int PLUS = 98; int MINUS = 99; int TIMES = 100; int DOUBLE_STAR = 101; int ELLIPSIS = 102; int DIVIDE = 103; int PERCENT = 104; int AND = 105; int OR = 106; int EXCLAM = 107; int COMMA = 108; int SEMICOLON = 109; int COLON = 110; int OPEN_BRACKET = 111; int CLOSE_BRACKET = 112; int OPEN_PAREN = 113; int CLOSE_PAREN = 114; int OPEN_BRACE = 115; int CLOSE_BRACE = 116; int IN = 117; int AS = 118; int USING = 119; int ID = 120; int LETTER = 121; int DIGIT = 122; int DIRECTIVE_END = 123; int EMPTY_DIRECTIVE_END = 124; int NATURAL_GT = 125; int NATURAL_GTE = 126; int TERMINATING_WHITESPACE = 127; int TERMINATING_EXCLAM = 128; int TERSE_COMMENT_END = 129; int MAYBE_END = 130; int KEEP_GOING = 131; int LONE_LESS_THAN_OR_DASH = 132; int DEFAULT = 0; int NODIRECTIVE = 1; int FM_EXPRESSION = 2; int IN_PAREN = 3; int NAMED_PARAMETER_EXPRESSION = 4; int EXPRESSION_COMMENT = 5; int NO_SPACE_EXPRESSION = 6; int NO_PARSE = 7; String[] tokenImage = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "<_INCLUDE>", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\"${\"", "\"#{\"", "", "", "", "\">\"", "\"]\"", "\"-\"", "", "", "", "", "\"false\"", "\"true\"", "", "", "\".\"", "\"..\"", "\"?\"", "\"??\"", "\"=\"", "\"==\"", "\"!=\"", "", "", "", "", "\"+\"", "\"-\"", "\"*\"", "\"**\"", "\"...\"", "\"/\"", "\"%\"", "", "", "\"!\"", "\",\"", "\";\"", "\":\"", "\"[\"", "\"]\"", "\"(\"", "\")\"", "\"{\"", "\"}\"", "\"in\"", "\"as\"", "\"using\"", "", "", "", "\">\"", "", "\">\"", "\">=\"", "", "", "", "", "", "", }; } libfreemarker-java-2.3.19.orig/src/freemarker/core/StringArraySequence.java0000644000175000017500000000742211723544471026306 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.SimpleScalar; import freemarker.template.TemplateModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; /** * Sequence variable implementation that wraps a String[] with relatively low * resource utilization. Warning: it does not copy the wrapped array, so do * not modify that after the model was made! * * @author Daniel Dekany * @version $Id: StringArraySequence.java,v 1.2 2004/01/06 17:06:42 szegedia Exp $ */ public class StringArraySequence implements TemplateSequenceModel { private String[] stringArray; private TemplateScalarModel[] array; /** * Warning: Does not copy the argument array! */ public StringArraySequence(String[] stringArray) { this.stringArray = stringArray; } public TemplateModel get(int index) { if (array == null) { array = new TemplateScalarModel[stringArray.length]; } TemplateScalarModel result = array[index]; if (result == null) { result = new SimpleScalar(stringArray[index]); array[index] = result; } return result; } public int size() { return stringArray.length; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Include.java0000644000175000017500000002015411723544470023727 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.cache.TemplateCache; import freemarker.template.*; import freemarker.template.utility.StringUtil; import freemarker.template.utility.UndeclaredThrowableException; /** * An instruction that gets another template * and processes it within the current template. */ final class Include extends TemplateElement { private Expression includedTemplateName, encodingExp, parseExp; private String encoding; private boolean parse; private final String templatePath; /** * @param template the template that this Include is a part of. * @param includedTemplateName the name of the template to be included. * @param encodingExp the encoding to be used or null, if it is a default. * @param parseExp whether the template should be parsed (or is raw text) */ Include(Template template, Expression includedTemplateName, Expression encodingExp, Expression parseExp) throws ParseException { String templatePath1 = template.getName(); int lastSlash = templatePath1.lastIndexOf('/'); templatePath = lastSlash == -1 ? "" : templatePath1.substring(0, lastSlash + 1); this.includedTemplateName = includedTemplateName; if (encodingExp instanceof StringLiteral) { encoding = encodingExp.toString(); encoding = encoding.substring(1, encoding.length() -1); } else { this.encodingExp = encodingExp; } if(parseExp == null) { parse = true; } else if(parseExp.isLiteral()) { try { if (parseExp instanceof StringLiteral) { parse = StringUtil.getYesNo(parseExp.getStringValue(null)); } else { try { parse = parseExp.isTrue(null); } catch(NonBooleanException e) { throw new ParseException("Expected a boolean or string as the value of the parse attribute", parseExp); } } } catch(TemplateException e) { // evaluation of literals must not throw a TemplateException throw new UndeclaredThrowableException(e); } } else { this.parseExp = parseExp; } } void accept(Environment env) throws TemplateException, IOException { String templateNameString = includedTemplateName.getStringValue(env); if( templateNameString == null ) { String msg = "Error " + getStartLocation() + "The expression " + includedTemplateName + " is undefined."; throw new InvalidReferenceException(msg, env); } String enc = encoding; if (encoding == null && encodingExp != null) { enc = encodingExp.getStringValue(env); } boolean parse = this.parse; if (parseExp != null) { TemplateModel tm = parseExp.getAsTemplateModel(env); if(tm == null) { if(env.isClassicCompatible()) { parse = false; } else { assertNonNull(tm, parseExp, env); } } if (tm instanceof TemplateScalarModel) { parse = getYesNo(EvaluationUtil.getString((TemplateScalarModel)tm, parseExp, env)); } else { parse = parseExp.isTrue(env); } } Template includedTemplate; try { templateNameString = TemplateCache.getFullTemplatePath(env, templatePath, templateNameString); includedTemplate = env.getTemplateForInclusion(templateNameString, enc, parse); } catch (ParseException pe) { String msg = "Error parsing included template " + templateNameString + "\n" + pe.getMessage(); throw new TemplateException(msg, pe, env); } catch (IOException ioe) { String msg = "Error reading included file " + templateNameString; throw new TemplateException(msg, ioe, env); } env.include(includedTemplate); } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#include "); buf.append(includedTemplateName); if (encoding != null) { buf.append(" encoding=\""); buf.append(encodingExp.getCanonicalForm()); buf.append("\""); } if(parseExp != null) { buf.append(" parse=" + parseExp.getCanonicalForm()); } else if (!parse) { buf.append(" parse=false"); } buf.append("/>"); return buf.toString(); } public String getDescription() { return "include " + includedTemplateName; } private boolean getYesNo(String s) throws ParseException { try { return StringUtil.getYesNo(s); } catch (IllegalArgumentException iae) { throw new ParseException("Error " + getStartLocation() + "\nValue of include parse parameter " + "must be boolean or one of these strings: " + "\"n\", \"no\", \"f\", \"false\", \"y\", \"yes\", \"t\", \"true\"" + "\nFound: " + parseExp, parseExp); } } /* boolean heedsOpeningWhitespace() { return true; } boolean heedsTrailingWhitespace() { return true; } */ } libfreemarker-java-2.3.19.orig/src/freemarker/core/Interpret.java0000644000175000017500000001536611723544471024332 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.*; import java.util.*; import freemarker.template.*; /** * A method that takes a parameter and evaluates it as a scalar, * then treats that scalar as template source code and returns a * transform model that evaluates the template in place. * The template inherits the configuration and environment of the executing * template. By default, its name will be equal to * executingTemplate.getName() + "$anonymous_interpreted". You can * specify another parameter to the method call in which case the * template name suffix is the specified id instead of "anonymous_interpreted". * @version $Id: Interpret.java,v 1.2 2005/06/16 18:13:56 ddekany Exp $ * @author Attila Szegedi */ class Interpret extends BuiltIn { /** * Constructs a template on-the-fly and returns it embedded in a * {@link TemplateTransformModel}. * *

The built-in has two arguments: * the arguments passed to the method. It can receive at * least one and at most two arguments, both must evaluate to a scalar. * The first scalar is interpreted as a template source code and a template * is built from it. The second (optional) is used to give the generated * template a name. * * @return a {@link TemplateTransformModel} that when executed inside * a <transform> block will process the generated template * just as if it had been <transform>-ed at that point. */ TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); Expression sourceExpr = null; String id = "anonymous_interpreted"; if(model instanceof TemplateSequenceModel) { sourceExpr = ((Expression)new DynamicKeyName(target, new NumberLiteral(new Integer(0))).copyLocationFrom(target)); if(((TemplateSequenceModel)model).size() > 1) { id = ((Expression)new DynamicKeyName(target, new NumberLiteral(new Integer(1))).copyLocationFrom(target)).getStringValue(env); } } else if (model instanceof TemplateScalarModel) { sourceExpr = target; } else { throw invalidTypeException(model, target, env, "sequence or string"); } String templateSource = sourceExpr.getStringValue(env); Template parentTemplate = env.getTemplate(); try { Template template = new Template(parentTemplate.getName() + "$" + id, new StringReader(templateSource), parentTemplate.getConfiguration()); template.setLocale(env.getLocale()); return new TemplateProcessorModel(template); } catch(IOException e) { throw new TemplateException("", e, env); } } private static class TemplateProcessorModel implements TemplateTransformModel { private final Template template; TemplateProcessorModel(Template template) { this.template = template; } public Writer getWriter(final Writer out, Map args) throws TemplateModelException, IOException { try { Environment env = Environment.getCurrentEnvironment(); env.include(template); } catch(TemplateModelException e) { throw e; } catch(IOException e) { throw e; } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new TemplateModelException(e); } return new Writer(out) { public void close() { } public void flush() throws IOException { out.flush(); } public void write(char[] cbuf, int off, int len) throws IOException { out.write(cbuf, off, len); } }; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Macro.java0000644000175000017500000002217511723544470023412 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.util.*; import freemarker.template.*; /** * An element representing a macro declaration. */ public final class Macro extends TemplateElement implements TemplateModel { private final String name; private final String[] argumentNames; private Map args; private String catchAll; boolean isFunction; static final Macro DO_NOTHING_MACRO = new Macro(".pass", Collections.EMPTY_LIST, freemarker.template.utility.Collections12.EMPTY_MAP, TextBlock.EMPTY_BLOCK); Macro(String name, List argumentNames, Map args, TemplateElement nestedBlock) { this.name = name; this.argumentNames = (String[])argumentNames.toArray( new String[argumentNames.size()]); this.args = args; this.nestedBlock = nestedBlock; } public String getCatchAll() { return catchAll; } public void setCatchAll(String value) { catchAll = value; } public String[] getArgumentNames() { return (String[])argumentNames.clone(); } String[] getArgumentNamesInternal() { return argumentNames; } boolean hasArgNamed(String name) { return args.containsKey(name); } public String getName() { return name; } void accept(Environment env) { env.visitMacroDef(this); } public String getCanonicalForm() { String directiveName = isFunction ? "function" : "macro"; StringBuffer buf = new StringBuffer("<#"); buf.append(directiveName); buf.append(' '); buf.append(name); buf.append('('); int size = argumentNames.length; for (int i = 0; i"); if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } buf.append("'); return buf.toString(); } public String getDescription() { return (isFunction() ? "function " : "macro ") + name; } public boolean isFunction() { return isFunction; } class Context implements LocalContext { Environment.Namespace localVars; TemplateElement body; Environment.Namespace bodyNamespace; List bodyParameterNames; Context prevMacroContext; ArrayList prevLocalContextStack; Context(Environment env, TemplateElement body, List bodyParameterNames) { this.localVars = env.new Namespace(); this.prevMacroContext = env.getCurrentMacroContext(); this.bodyNamespace = env.getCurrentNamespace(); this.prevLocalContextStack = env.getLocalContextStack(); this.body = body; this.bodyParameterNames = bodyParameterNames; } Macro getMacro() { return Macro.this; } void runMacro(Environment env) throws TemplateException, IOException { sanityCheck(env); // Set default values for unspecified parameters if (nestedBlock != null) { env.visit(nestedBlock); } } // Set default parameters, check if all the required parameters are defined. void sanityCheck(Environment env) throws TemplateException { boolean resolvedAnArg, hasUnresolvedArg; Expression firstUnresolvedExpression; InvalidReferenceException firstReferenceException; do { firstUnresolvedExpression = null; firstReferenceException = null; resolvedAnArg = hasUnresolvedArg = false; for(int i = 0; i < argumentNames.length; ++i) { String argName = argumentNames[i]; if(localVars.get(argName) == null) { Expression valueExp = (Expression) args.get(argName); if (valueExp != null) { try { TemplateModel tm = valueExp.getAsTemplateModel(env); if(tm == null) { if(!hasUnresolvedArg) { firstUnresolvedExpression = valueExp; hasUnresolvedArg = true; } } else { localVars.put(argName, tm); resolvedAnArg = true; } } catch(InvalidReferenceException e) { if(!hasUnresolvedArg) { hasUnresolvedArg = true; firstReferenceException = e; } } } else { throw new TemplateException("Error executing macro: " + name + "\nrequired parameter: " + argName + " is not specified.", env); } } } } while(resolvedAnArg && hasUnresolvedArg); if(hasUnresolvedArg) { if(firstReferenceException != null) { throw firstReferenceException; } else { assertNonNull(null, firstUnresolvedExpression, env); } } } /** * @return the local variable of the given name * or null if it doesn't exist. */ public TemplateModel getLocalVariable(String name) throws TemplateModelException { return localVars.get(name); } Environment.Namespace getLocals() { return localVars; } /** * Set a local variable in this macro */ void setLocalVar(String name, TemplateModel var) { localVars.put(name, var); } public Collection getLocalVariableNames() throws TemplateModelException { HashSet result = new HashSet(); for (TemplateModelIterator it = localVars.keys().iterator(); it.hasNext();) { result.add(it.next().toString()); } return result; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FMParser.java0000644000175000017500000041504511723544471024033 0ustar ebourgebourg/* Generated By:JavaCC: Do not edit this line. FMParser.java */ package freemarker.core; import freemarker.template.*; import freemarker.template.utility.StringUtil; import freemarker.template.utility.DeepUnwrap; import java.io.*; import java.util.*; /** * This class is generated by JavaCC from a grammar file. */ public class FMParser implements FMParserConstants { // Necessary for adding macros and setting location info. Template template; private String templateName; // variables that keep track of whether we are in a loop or a switch. private int loopNesting, switchNesting; private boolean inMacro, inFunction, stripWhitespace, stripText; private LinkedList escapes = new LinkedList(); private int contentNesting; // for stripText /** * Create an FM expression parser using a string. */ static public FMParser createExpressionParser(String s) { SimpleCharStream scs = new SimpleCharStream(new StringReader(s), 1, 1, s.length()); FMParserTokenManager token_source = new FMParserTokenManager(scs); token_source.SwitchTo(FMParserConstants.FM_EXPRESSION); return new FMParser(token_source); } /** * Constructs a new parser object. * @param template The template associated with this parser. * @param reader The character stream to use as input * @param strictEscapeSyntax Whether FreeMarker directives must start with a # */ public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace) { this(reader); this.template = template; token_source.strictEscapeSyntax = strictEscapeSyntax; this.templateName = template != null ? template.getName() : ""; token_source.templateName = templateName; this.stripWhitespace = stripWhitespace; } public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax) { this(template, reader, strictEscapeSyntax, stripWhitespace, tagSyntax, Configuration.PARSED_DEFAULT_INCOMPATIBLE_ENHANCEMENTS); } public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax, int incompatibleChanges) { this(template, reader, strictEscapeSyntax, stripWhitespace); switch (tagSyntax) { case Configuration.AUTO_DETECT_TAG_SYNTAX : token_source.autodetectTagSyntax = true; break; case Configuration.ANGLE_BRACKET_TAG_SYNTAX : token_source.altDirectiveSyntax = false; break; case Configuration.SQUARE_BRACKET_TAG_SYNTAX : token_source.altDirectiveSyntax = true; break; default : throw new IllegalArgumentException("Illegal argument for tagSyntax"); } token_source.incompatibleChanges = incompatibleChanges; } public FMParser(String template) { this(null, new StringReader(template), true, true); } private String getErrorStart(Token t) { return "Error in template: " + template.getName() + "\non line " + t.beginLine + ", column " + t.beginColumn; } /** * Throw an exception if the expression passed in is a String * Literal */ private void notStringLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof StringLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound string literal: " + exp + "\nExpecting: " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a Number * Literal */ private void notNumberLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof NumberLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound number literal: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a boolean * Literal */ private void notBooleanLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof BooleanLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a Hash * Literal */ private void notHashLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof HashLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound hash literal: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a List * Literal */ private void notListLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof ListLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound list literal: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a literal * other than of the numerical type */ private void numberLiteralOnly(Expression exp) throws ParseException { notStringLiteral(exp, "number"); notListLiteral(exp, "number"); notHashLiteral(exp, "number"); notBooleanLiteral(exp, "number"); } /** * Throw an exception if the expression passed in is * not a string. */ private void stringLiteralOnly(Expression exp) throws ParseException { notNumberLiteral(exp, "number"); notListLiteral(exp, "number"); notHashLiteral(exp, "number"); notBooleanLiteral(exp, "number"); } /** * Throw an exception if the expression passed in is a literal * other than of the boolean type */ private void booleanLiteralOnly(Expression exp) throws ParseException { notStringLiteral(exp, "boolean (true/false)"); notListLiteral(exp, "boolean (true/false)"); notHashLiteral(exp, "boolean (true/false)"); notNumberLiteral(exp, "boolean (true/false)"); } private Expression escapedExpression(Expression exp) { if(!escapes.isEmpty()) { return ((EscapeBlock)escapes.getFirst()).doEscape(exp); } return exp; } private boolean getBoolean(Expression exp) throws ParseException { TemplateModel tm = null; try { tm = exp.getAsTemplateModel(null); } catch (Exception e) { throw new ParseException(e.getMessage() + "\nCould not evaluate expression: " + exp.getCanonicalForm() + exp.getStartLocation(), exp); } if (tm instanceof TemplateBooleanModel) { try { return ((TemplateBooleanModel) tm).getAsBoolean(); } catch (TemplateModelException tme) { } } if (tm instanceof TemplateScalarModel) { try { return StringUtil.getYesNo(((TemplateScalarModel) tm).getAsString()); } catch (Exception e) { throw new ParseException(e.getMessage() + "\nExpecting yes/no, found: " + exp.getCanonicalForm() + exp.getStartLocation(), exp); } } throw new ParseException("Expecting boolean (yes/no) parameter" + exp.getStartLocation(), exp); } // Now the actual parsing code, starting // with the productions for FreeMarker's // expression syntax. /** * This is the same as OrExpression, since * the OR is the operator with the lowest * precedence. */ final public Expression Expression() throws ParseException { Expression exp; exp = OrExpression(); {if (true) return exp;} throw new Error("Missing return statement in function"); } /** * Lowest level expression, a literal, a variable, * or a possibly more complex expression bounded * by parentheses. */ final public Expression PrimaryExpression() throws ParseException { Expression exp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case INTEGER: case DECIMAL: exp = NumberLiteral(); break; case OPEN_BRACE: exp = HashLiteral(); break; case STRING_LITERAL: case RAW_STRING: exp = StringLiteral(true); break; case FALSE: case TRUE: exp = BooleanLiteral(); break; case OPEN_BRACKET: exp = ListLiteral(); break; case ID: exp = Identifier(); break; case OPEN_PAREN: exp = Parenthesis(); break; case DOT: exp = BuiltinVariable(); break; default: jj_la1[0] = jj_gen; jj_consume_token(-1); throw new ParseException(); } label_1: while (true) { if (jj_2_1(2147483647)) { ; } else { break label_1; } exp = AddSubExpression(exp); } {if (true) return exp;} throw new Error("Missing return statement in function"); } final public Expression Parenthesis() throws ParseException { Expression exp, result; Token start, end; start = jj_consume_token(OPEN_PAREN); exp = Expression(); end = jj_consume_token(CLOSE_PAREN); result = new ParentheticalExpression(exp); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * A primary expression preceded by zero or * more unary operators. (The only unary operator we * currently have is the NOT.) */ final public Expression UnaryExpression() throws ParseException { Expression exp, result; boolean haveNot = false; Token t = null, start=null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case PLUS: case MINUS: result = UnaryPlusMinusExpression(); break; case EXCLAM: result = NotExpression(); break; case STRING_LITERAL: case RAW_STRING: case FALSE: case TRUE: case INTEGER: case DECIMAL: case DOT: case OPEN_BRACKET: case OPEN_PAREN: case OPEN_BRACE: case ID: result = PrimaryExpression(); break; default: jj_la1[1] = jj_gen; jj_consume_token(-1); throw new ParseException(); } {if (true) return result;} throw new Error("Missing return statement in function"); } final public Expression NotExpression() throws ParseException { Token t; Expression exp, result=null; ArrayList nots = new ArrayList(); label_2: while (true) { t = jj_consume_token(EXCLAM); nots.add(t); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EXCLAM: ; break; default: jj_la1[2] = jj_gen; break label_2; } } exp = PrimaryExpression(); for (int i=0; i + keyname */ final public Expression DotVariable(Expression exp) throws ParseException { Token t; jj_consume_token(DOT); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: t = jj_consume_token(ID); break; case TIMES: t = jj_consume_token(TIMES); break; case DOUBLE_STAR: t = jj_consume_token(DOUBLE_STAR); break; case FALSE: case TRUE: case LESS_THAN: case LESS_THAN_EQUALS: case ESCAPED_GT: case ESCAPED_GTE: case IN: case AS: case USING: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case LESS_THAN: t = jj_consume_token(LESS_THAN); break; case LESS_THAN_EQUALS: t = jj_consume_token(LESS_THAN_EQUALS); break; case ESCAPED_GT: t = jj_consume_token(ESCAPED_GT); break; case ESCAPED_GTE: t = jj_consume_token(ESCAPED_GTE); break; case FALSE: t = jj_consume_token(FALSE); break; case TRUE: t = jj_consume_token(TRUE); break; case IN: t = jj_consume_token(IN); break; case AS: t = jj_consume_token(AS); break; case USING: t = jj_consume_token(USING); break; default: jj_la1[12] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (!Character.isLetter(t.image.charAt(0))) { String msg = getErrorStart(t) + "\n" + t.image + " is not a valid identifier."; {if (true) throw new ParseException(msg, t.beginLine, t.beginColumn);} } break; default: jj_la1[13] = jj_gen; jj_consume_token(-1); throw new ParseException(); } notListLiteral(exp, "hash"); notStringLiteral(exp, "hash"); notBooleanLiteral(exp, "hash"); Dot dot = new Dot(exp, t.image); dot.setLocation(template, exp, t); {if (true) return dot;} throw new Error("Missing return statement in function"); } /** * production for when the key is specified * in brackets. */ final public Expression DynamicKey(Expression exp) throws ParseException { Expression arg; Token t; jj_consume_token(OPEN_BRACKET); arg = Expression(); t = jj_consume_token(CLOSE_BRACKET); notBooleanLiteral(exp, "list or hash"); notNumberLiteral(exp, "list or hash"); DynamicKeyName dkn = new DynamicKeyName(exp, arg); dkn.setLocation(template, exp, t); {if (true) return dkn;} throw new Error("Missing return statement in function"); } /** * production for an arglist part of a method invocation. */ final public MethodCall MethodArgs(Expression exp) throws ParseException { ArrayList args = new ArrayList(); Token end; jj_consume_token(OPEN_PAREN); args = PositionalArgs(); end = jj_consume_token(CLOSE_PAREN); args.trimToSize(); MethodCall result = new MethodCall(exp, args); result.setLocation(template, exp, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public StringLiteral StringLiteral(boolean interpolate) throws ParseException { Token t; boolean raw = false; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case STRING_LITERAL: t = jj_consume_token(STRING_LITERAL); break; case RAW_STRING: t = jj_consume_token(RAW_STRING); raw = true; break; default: jj_la1[14] = jj_gen; jj_consume_token(-1); throw new ParseException(); } String s = t.image; // Get rid of the quotes. s = s.substring(1, s.length() -1); if (raw) { s=s.substring(1); } else try { s = StringUtil.FTLStringLiteralDec(s); } catch (ParseException pe) { pe.lineNumber = t.beginLine; pe.columnNumber = t.beginColumn; {if (true) throw pe;} } StringLiteral result = new StringLiteral(s); result.setLocation(template, t, t); if (interpolate && !raw) { if (t.image.indexOf("${") >=0 || t.image.indexOf("#{") >=0) result.checkInterpolation(); } {if (true) return result;} throw new Error("Missing return statement in function"); } final public Expression BooleanLiteral() throws ParseException { Token t; Expression result; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case FALSE: t = jj_consume_token(FALSE); result = new BooleanLiteral(false); break; case TRUE: t = jj_consume_token(TRUE); result = new BooleanLiteral(true); break; default: jj_la1[15] = jj_gen; jj_consume_token(-1); throw new ParseException(); } result.setLocation(template, t, t); {if (true) return result;} throw new Error("Missing return statement in function"); } final public HashLiteral HashLiteral() throws ParseException { Token begin, end; Expression key, value; ArrayList keys = new ArrayList(); ArrayList values = new ArrayList(); begin = jj_consume_token(OPEN_BRACE); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case STRING_LITERAL: case RAW_STRING: case FALSE: case TRUE: case INTEGER: case DECIMAL: case DOT: case PLUS: case MINUS: case EXCLAM: case OPEN_BRACKET: case OPEN_PAREN: case OPEN_BRACE: case ID: key = Expression(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: jj_consume_token(COMMA); break; case COLON: jj_consume_token(COLON); break; default: jj_la1[16] = jj_gen; jj_consume_token(-1); throw new ParseException(); } value = Expression(); stringLiteralOnly(key); keys.add(key); values.add(value); label_7: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: ; break; default: jj_la1[17] = jj_gen; break label_7; } jj_consume_token(COMMA); key = Expression(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: jj_consume_token(COMMA); break; case COLON: jj_consume_token(COLON); break; default: jj_la1[18] = jj_gen; jj_consume_token(-1); throw new ParseException(); } value = Expression(); stringLiteralOnly(key); keys.add(key); values.add(value); } break; default: jj_la1[19] = jj_gen; ; } end = jj_consume_token(CLOSE_BRACE); HashLiteral result = new HashLiteral(keys, values); result.setLocation(template, begin, end); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * A production representing the ${...} * that outputs a variable. */ final public DollarVariable StringOutput() throws ParseException { Expression exp; Token begin, end; begin = jj_consume_token(OUTPUT_ESCAPE); exp = Expression(); notHashLiteral(exp, "scalar"); notListLiteral(exp, "scalar"); notBooleanLiteral(exp, "scalar"); end = jj_consume_token(CLOSE_BRACE); DollarVariable result = new DollarVariable(exp, escapedExpression(exp)); result.setLocation(template, begin, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public NumericalOutput NumericalOutput() throws ParseException { Expression exp; Token fmt = null, begin, end; begin = jj_consume_token(NUMERICAL_ESCAPE); exp = Expression(); numberLiteralOnly(exp); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SEMICOLON: jj_consume_token(SEMICOLON); fmt = jj_consume_token(ID); break; default: jj_la1[20] = jj_gen; ; } end = jj_consume_token(CLOSE_BRACE); NumericalOutput result; if (fmt != null) { int minFrac = -1; // -1 indicates that the value has not been set int maxFrac = -1; StringTokenizer st = new StringTokenizer(fmt.image, "mM", true); char type = '-'; while (st.hasMoreTokens()) { String token = st.nextToken(); try { if (type != '-') { switch (type) { case 'm': if (minFrac != -1) {if (true) throw new ParseException("invalid formatting string", fmt.beginLine, fmt.beginColumn);} minFrac = Integer.parseInt(token); break; case 'M': if (maxFrac != -1) {if (true) throw new ParseException("invalid formatting string", fmt.beginLine, fmt.beginColumn);} maxFrac = Integer.parseInt(token); break; default: {if (true) throw new ParseException();} } type = '-'; } else if (token.equals("m")) { type = 'm'; } else if (token.equals("M")) { type = 'M'; } else { {if (true) throw new ParseException();} } } catch (ParseException e) { String msg = getErrorStart(fmt) + "\nInvalid format specifier " + fmt.image; {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);} } catch (NumberFormatException e) { String msg = getErrorStart(fmt) + "\nInvalid number in the format specifier " + fmt.image; {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);} } } if (maxFrac == -1) { if (minFrac == -1) { String msg = getErrorStart(fmt) + "\nInvalid format specification, at least one of m and M must be specified!"; {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);} } maxFrac = minFrac; } else if (minFrac == -1) { minFrac = 0; } if (minFrac > maxFrac) { String msg = getErrorStart(fmt) + "\nInvalid format specification, min cannot be greater than max!"; {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);} } if (minFrac > 50 || maxFrac > 50) {// sanity check String msg = getErrorStart(fmt) + "\nCannot specify more than 50 fraction digits"; {if (true) throw new ParseException(msg, fmt.beginLine, fmt.beginColumn);} } result = new NumericalOutput(exp, minFrac, maxFrac); } else { // if format != null result = new NumericalOutput(exp); } result.setLocation(template, begin, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TemplateElement If() throws ParseException { Token start, end, t; Expression condition; TemplateElement block; IfBlock ifBlock; ConditionalBlock cblock; start = jj_consume_token(IF); condition = Expression(); jj_consume_token(DIRECTIVE_END); block = OptionalBlock(); cblock = new ConditionalBlock(condition, block, true); cblock.setLocation(template, start, block); ifBlock = new IfBlock(cblock); label_8: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ELSE_IF: ; break; default: jj_la1[21] = jj_gen; break label_8; } t = jj_consume_token(ELSE_IF); condition = Expression(); LooseDirectiveEnd(); block = OptionalBlock(); cblock = new ConditionalBlock(condition, block, false); cblock.setLocation(template, t, block); ifBlock.addBlock(cblock); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ELSE: t = jj_consume_token(ELSE); block = OptionalBlock(); cblock = new ConditionalBlock(null, block, false); cblock.setLocation(template, t, block); ifBlock.addBlock(cblock); break; default: jj_la1[22] = jj_gen; ; } end = jj_consume_token(END_IF); ifBlock.setLocation(template, start, end); {if (true) return ifBlock;} throw new Error("Missing return statement in function"); } final public AttemptBlock Attempt() throws ParseException { Token start, end; TemplateElement block, recoveryBlock; start = jj_consume_token(ATTEMPT); block = OptionalBlock(); recoveryBlock = Recover(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case END_RECOVER: end = jj_consume_token(END_RECOVER); break; case END_ATTEMPT: end = jj_consume_token(END_ATTEMPT); break; default: jj_la1[23] = jj_gen; jj_consume_token(-1); throw new ParseException(); } AttemptBlock result = new AttemptBlock(block, recoveryBlock); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public RecoveryBlock Recover() throws ParseException { Token start; TemplateElement block; start = jj_consume_token(RECOVER); block = OptionalBlock(); RecoveryBlock result = new RecoveryBlock(block); result.setLocation(template, start, block); {if (true) return result;} throw new Error("Missing return statement in function"); } final public IteratorBlock List() throws ParseException { Expression exp; Token index, start, end; TemplateElement block; start = jj_consume_token(LIST); ++loopNesting; exp = Expression(); jj_consume_token(AS); index = jj_consume_token(ID); jj_consume_token(DIRECTIVE_END); block = OptionalBlock(); end = jj_consume_token(END_LIST); --loopNesting; IteratorBlock result = new IteratorBlock(exp, index.image, block, false); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public IteratorBlock ForEach() throws ParseException { Expression exp; Token index, start, end; TemplateElement block; start = jj_consume_token(FOREACH); ++loopNesting; index = jj_consume_token(ID); jj_consume_token(IN); exp = Expression(); jj_consume_token(DIRECTIVE_END); block = OptionalBlock(); end = jj_consume_token(END_FOREACH); --loopNesting; IteratorBlock result = new IteratorBlock(exp, index.image, block, true); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public VisitNode Visit() throws ParseException { Token start, end; Expression targetNode, namespaces=null; start = jj_consume_token(VISIT); targetNode = Expression(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case USING: jj_consume_token(USING); namespaces = Expression(); break; default: jj_la1[24] = jj_gen; ; } end = LooseDirectiveEnd(); VisitNode result = new VisitNode(targetNode, namespaces); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public RecurseNode Recurse() throws ParseException { Token start, end = null; Expression node=null, namespaces=null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SIMPLE_RECURSE: start = jj_consume_token(SIMPLE_RECURSE); break; case RECURSE: start = jj_consume_token(RECURSE); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case STRING_LITERAL: case RAW_STRING: case FALSE: case TRUE: case INTEGER: case DECIMAL: case DOT: case PLUS: case MINUS: case EXCLAM: case OPEN_BRACKET: case OPEN_PAREN: case OPEN_BRACE: case ID: node = Expression(); break; default: jj_la1[25] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case USING: jj_consume_token(USING); namespaces = Expression(); break; default: jj_la1[26] = jj_gen; ; } end = LooseDirectiveEnd(); break; default: jj_la1[27] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (end == null) end = start; RecurseNode result = new RecurseNode(node, namespaces); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public FallbackInstruction FallBack() throws ParseException { Token tok; tok = jj_consume_token(FALLBACK); if (!inMacro) { {if (true) throw new ParseException(getErrorStart(tok) + "\nCannot fall back " + " outside a macro.", tok.beginLine, tok.beginColumn);} } FallbackInstruction result = new FallbackInstruction(); result.setLocation(template, tok, tok); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * Production used to break out of a loop or a switch block. */ final public BreakInstruction Break() throws ParseException { Token start; start = jj_consume_token(BREAK); if (loopNesting < 1 && switchNesting <1) { String msg = getErrorStart(start) + "\n" + start.image + " occurred outside a loop or a switch block."; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } BreakInstruction result = new BreakInstruction(); result.setLocation(template, start, start); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * Production used to jump out of a macro. * The stop instruction terminates the rendering of the template. */ final public ReturnInstruction Return() throws ParseException { Token start, end=null; Expression exp = null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SIMPLE_RETURN: start = jj_consume_token(SIMPLE_RETURN); end = start; break; case RETURN: start = jj_consume_token(RETURN); exp = Expression(); end = LooseDirectiveEnd(); break; default: jj_la1[28] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (inMacro) { if (exp != null) { String msg = getErrorStart(start) + "\nA macro cannot return a value"; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } } else if (inFunction) { if (exp == null) { String msg = getErrorStart(start) + "\nA function must return a value"; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } } else { if (exp == null) { String msg = getErrorStart(start) + "\nA return instruction can only occur inside a macro of function"; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } } ReturnInstruction result = new ReturnInstruction(exp); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public StopInstruction Stop() throws ParseException { Token start = null; Expression exp = null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case HALT: start = jj_consume_token(HALT); break; case STOP: start = jj_consume_token(STOP); exp = Expression(); LooseDirectiveEnd(); break; default: jj_la1[29] = jj_gen; jj_consume_token(-1); throw new ParseException(); } StopInstruction result = new StopInstruction(exp); result.setLocation(template, start, start); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TemplateElement Nested() throws ParseException { Token t, end; ArrayList bodyParameters; BodyInstruction result = null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SIMPLE_NESTED: t = jj_consume_token(SIMPLE_NESTED); result = new BodyInstruction(null); result.setLocation(template, t, t); break; case NESTED: t = jj_consume_token(NESTED); bodyParameters = PositionalArgs(); end = LooseDirectiveEnd(); result = new BodyInstruction(bodyParameters); result.setLocation(template, t, end); break; default: jj_la1[30] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (!inMacro) { {if (true) throw new ParseException(getErrorStart(t) + "\nCannot use a " + t.image + " instruction outside a macro.", t.beginLine, t.beginColumn);} } {if (true) return result;} throw new Error("Missing return statement in function"); } final public TemplateElement Flush() throws ParseException { Token t; t = jj_consume_token(FLUSH); FlushInstruction result = new FlushInstruction(); result.setLocation(template, t, t); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TemplateElement Trim() throws ParseException { Token t; TrimInstruction result=null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TRIM: t = jj_consume_token(TRIM); result = new TrimInstruction(true, true); break; case LTRIM: t = jj_consume_token(LTRIM); result = new TrimInstruction(true, false); break; case RTRIM: t = jj_consume_token(RTRIM); result = new TrimInstruction(false, true); break; case NOTRIM: t = jj_consume_token(NOTRIM); result = new TrimInstruction(false, false); break; default: jj_la1[31] = jj_gen; jj_consume_token(-1); throw new ParseException(); } result.setLocation(template, t, t); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TemplateElement Assign() throws ParseException { Token start, end; int scope; Token id=null; Expression nameExp, exp, nsExp=null; String varName; ArrayList assignments = new ArrayList(); Assignment ass; TemplateElement block; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ASSIGN: start = jj_consume_token(ASSIGN); scope = Assignment.NAMESPACE; break; case GLOBALASSIGN: start = jj_consume_token(GLOBALASSIGN); scope = Assignment.GLOBAL; break; case LOCALASSIGN: start = jj_consume_token(LOCALASSIGN); scope = Assignment.LOCAL; scope = Assignment.LOCAL; if (!inMacro && !inFunction) { String msg = getErrorStart(start) + "\nLocal variable assigned outside a macro."; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } break; default: jj_la1[32] = jj_gen; jj_consume_token(-1); throw new ParseException(); } nameExp = IdentifierOrStringLiteral(); varName = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EQUALS: jj_consume_token(EQUALS); exp = Expression(); ass = new Assignment(varName, exp, scope); ass.setLocation(template, nameExp, exp); assignments.add(ass); label_9: while (true) { if (jj_2_11(2147483647)) { ; } else { break label_9; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: jj_consume_token(COMMA); break; default: jj_la1[33] = jj_gen; ; } nameExp = IdentifierOrStringLiteral(); varName = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString(); jj_consume_token(EQUALS); exp = Expression(); ass = new Assignment(varName, exp, scope); ass.setLocation(template, nameExp, exp); assignments.add(ass); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case IN: id = jj_consume_token(IN); nsExp = Expression(); if (scope != Assignment.NAMESPACE) {if (true) throw new ParseException(getErrorStart(id) + "\nCannot assign to namespace here.", id.beginLine, id.beginColumn);} break; default: jj_la1[34] = jj_gen; ; } end = LooseDirectiveEnd(); AssignmentInstruction ai = new AssignmentInstruction(scope); for (int i = 0; i< assignments.size(); i++) { ai.addAssignment((Assignment) assignments.get(i)); } ai.setNamespaceExp(nsExp); ai.setLocation(template, start, end); {if (true) return ai;} break; case IN: case DIRECTIVE_END: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case IN: id = jj_consume_token(IN); nsExp = Expression(); if (scope != Assignment.NAMESPACE) {if (true) throw new ParseException(getErrorStart(id) + "\nCannot assign to namespace here.", id.beginLine, id.beginColumn);} break; default: jj_la1[35] = jj_gen; ; } jj_consume_token(DIRECTIVE_END); block = OptionalBlock(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case END_LOCAL: end = jj_consume_token(END_LOCAL); if (scope != Assignment.LOCAL) {if (true) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags.", end.beginLine, end.beginColumn);} break; case END_ASSIGN: end = jj_consume_token(END_ASSIGN); if (scope != Assignment.NAMESPACE) {if (true) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags.", end.beginLine, end.beginColumn);} break; case END_GLOBAL: end = jj_consume_token(END_GLOBAL); if (scope != Assignment.GLOBAL) {if (true) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags", end.beginLine, end.beginColumn);} break; default: jj_la1[36] = jj_gen; jj_consume_token(-1); throw new ParseException(); } BlockAssignment ba = new BlockAssignment(block, varName, scope, nsExp); ba.setLocation(template, start, end); {if (true) return ba;} break; default: jj_la1[37] = jj_gen; jj_consume_token(-1); throw new ParseException(); } throw new Error("Missing return statement in function"); } final public Include Include() throws ParseException { Expression nameExp; Token att, start, end; Expression exp, parseExp = null, encodingExp = null; start = jj_consume_token(_INCLUDE); nameExp = Expression(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SEMICOLON: jj_consume_token(SEMICOLON); break; default: jj_la1[38] = jj_gen; ; } label_10: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: ; break; default: jj_la1[39] = jj_gen; break label_10; } att = jj_consume_token(ID); jj_consume_token(EQUALS); exp = Expression(); String attString = att.image; if (attString.equalsIgnoreCase("parse")) { parseExp = exp; } else if (attString.equalsIgnoreCase("encoding")) { encodingExp = exp; } else { String msg = getErrorStart(att) + "\nexpecting parse= or encoding= to be specified."; {if (true) throw new ParseException(msg, att.beginLine, att.beginColumn);} } } end = LooseDirectiveEnd(); Include result = new Include(template, nameExp, encodingExp, parseExp); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public LibraryLoad Import() throws ParseException { Token start, end, ns; Expression nameExp; start = jj_consume_token(IMPORT); nameExp = Expression(); jj_consume_token(AS); ns = jj_consume_token(ID); end = LooseDirectiveEnd(); LibraryLoad result = new LibraryLoad(template, nameExp, ns.image); result.setLocation(template, start, end); template.addImport(result); {if (true) return result;} throw new Error("Missing return statement in function"); } final public Macro Macro() throws ParseException { Token arg, start, end; Expression nameExp; String name; ArrayList argNames = new ArrayList(); HashMap args = new HashMap(); ArrayList defNames = new ArrayList(); Expression defValue=null; TemplateElement block; boolean isFunction = false, hasDefaults=false; boolean isCatchAll = false; String catchAll = null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case MACRO: start = jj_consume_token(MACRO); break; case FUNCTION: start = jj_consume_token(FUNCTION); isFunction = true; break; default: jj_la1[40] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (inMacro || inFunction) { {if (true) throw new ParseException(getErrorStart(start) + "\nMacros cannot be nested.", start.beginLine, start.endLine);} } if (isFunction) inFunction = true; else inMacro = true; nameExp = IdentifierOrStringLiteral(); name = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case OPEN_PAREN: jj_consume_token(OPEN_PAREN); break; default: jj_la1[41] = jj_gen; ; } label_11: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: ; break; default: jj_la1[42] = jj_gen; break label_11; } arg = jj_consume_token(ID); defValue = null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ELLIPSIS: jj_consume_token(ELLIPSIS); isCatchAll = true; break; default: jj_la1[43] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EQUALS: jj_consume_token(EQUALS); defValue = Expression(); defNames.add(arg.image); hasDefaults = true; break; default: jj_la1[44] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: jj_consume_token(COMMA); break; default: jj_la1[45] = jj_gen; ; } if (catchAll != null) { {if (true) throw new ParseException(getErrorStart(arg) + "\nThere may only be one \"catch-all\" parameter in a macro declaration, " + "and it must be the last parameter.", arg.beginLine, arg.endLine);} } if (isCatchAll) { if (defValue != null) { {if (true) throw new ParseException(getErrorStart(arg) + "\n\"Catch-all\" macro parameter may not have a default value.", arg.beginLine, arg.endLine);} } catchAll = arg.image; } else { argNames.add(arg.image); if (hasDefaults && defValue == null) { {if (true) throw new ParseException(getErrorStart(arg) + "\nIn a macro declaration, parameters without a default value " + "must all occur before the parameters with default values.", arg.beginLine, arg.endLine);} } args.put(arg.image, defValue); } } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case CLOSE_PAREN: jj_consume_token(CLOSE_PAREN); break; default: jj_la1[46] = jj_gen; ; } jj_consume_token(DIRECTIVE_END); block = OptionalBlock(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case END_MACRO: end = jj_consume_token(END_MACRO); if(isFunction) {if (true) throw new ParseException(getErrorStart(start) + "\nExpected function end tag here.", start.beginLine, start.endLine);} break; case END_FUNCTION: end = jj_consume_token(END_FUNCTION); if(!isFunction) {if (true) throw new ParseException(getErrorStart(start) + "\nExpected macro end tag here.", start.beginLine, start.endLine);} break; default: jj_la1[47] = jj_gen; jj_consume_token(-1); throw new ParseException(); } inMacro = inFunction = false; Macro result = new Macro(name, argNames, args, block); result.setCatchAll(catchAll); result.isFunction = isFunction; result.setLocation(template, start, end); template.addMacro(result); {if (true) return result;} throw new Error("Missing return statement in function"); } final public CompressedBlock Compress() throws ParseException { TemplateElement block; Token start, end; start = jj_consume_token(COMPRESS); block = OptionalBlock(); end = jj_consume_token(END_COMPRESS); CompressedBlock cb = new CompressedBlock(block); cb.setLocation(template, start, end); {if (true) return cb;} throw new Error("Missing return statement in function"); } final public TemplateElement UnifiedMacroTransform() throws ParseException { Token start=null, end, t; HashMap namedArgs = null; ArrayList positionalArgs = null, bodyParameters = null; String directiveName = null; TemplateElement nestedBlock = null; Expression exp; start = jj_consume_token(UNIFIED_CALL); exp = Expression(); if (exp instanceof Identifier || (exp instanceof Dot && ((Dot) exp).onlyHasIdentifiers())) { directiveName = exp.getCanonicalForm(); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TERMINATING_WHITESPACE: jj_consume_token(TERMINATING_WHITESPACE); break; default: jj_la1[48] = jj_gen; ; } if (jj_2_12(2147483647)) { namedArgs = NamedArgs(); } else { positionalArgs = PositionalArgs(); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SEMICOLON: jj_consume_token(SEMICOLON); bodyParameters = new ArrayList(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: case TERMINATING_WHITESPACE: switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TERMINATING_WHITESPACE: jj_consume_token(TERMINATING_WHITESPACE); break; default: jj_la1[49] = jj_gen; ; } t = jj_consume_token(ID); bodyParameters.add(t.image); label_12: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: case TERMINATING_WHITESPACE: ; break; default: jj_la1[50] = jj_gen; break label_12; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TERMINATING_WHITESPACE: jj_consume_token(TERMINATING_WHITESPACE); break; default: jj_la1[51] = jj_gen; ; } jj_consume_token(COMMA); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TERMINATING_WHITESPACE: jj_consume_token(TERMINATING_WHITESPACE); break; default: jj_la1[52] = jj_gen; ; } t = jj_consume_token(ID); bodyParameters.add(t.image); } break; default: jj_la1[53] = jj_gen; ; } break; default: jj_la1[54] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EMPTY_DIRECTIVE_END: end = jj_consume_token(EMPTY_DIRECTIVE_END); break; case DIRECTIVE_END: jj_consume_token(DIRECTIVE_END); nestedBlock = OptionalBlock(); end = jj_consume_token(UNIFIED_CALL_END); String s = end.image.substring(3); s = s.substring(0, s.length() -1).trim(); if (s.length() >0 && !s.equals(directiveName)) { String msg = getErrorStart(end); if (directiveName == null) { {if (true) throw new ParseException(msg + "\nExpecting ", end.beginLine, end.beginColumn);} } else { {if (true) throw new ParseException(msg + "\nExpecting or ", end.beginLine, end.beginColumn);} } } break; default: jj_la1[55] = jj_gen; jj_consume_token(-1); throw new ParseException(); } TemplateElement result = (positionalArgs != null) ? new UnifiedCall(exp, positionalArgs, nestedBlock, bodyParameters) : new UnifiedCall(exp, namedArgs, nestedBlock, bodyParameters); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TemplateElement Call() throws ParseException { Token start, end, id; HashMap namedArgs = null; ArrayList positionalArgs = null; String macroName= null; start = jj_consume_token(CALL); id = jj_consume_token(ID); macroName = id.image; if (jj_2_14(2147483647)) { namedArgs = NamedArgs(); } else { if (jj_2_13(2147483647)) { jj_consume_token(OPEN_PAREN); } else { ; } positionalArgs = PositionalArgs(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case CLOSE_PAREN: jj_consume_token(CLOSE_PAREN); break; default: jj_la1[56] = jj_gen; ; } } end = LooseDirectiveEnd(); UnifiedCall result = null; if (positionalArgs != null) { result = new UnifiedCall(new Identifier(macroName), positionalArgs, null, null); } else { result = new UnifiedCall(new Identifier(macroName), namedArgs, null, null); } result.legacySyntax = true; result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public HashMap NamedArgs() throws ParseException { HashMap result = new HashMap(); Token t; Expression exp; label_13: while (true) { t = jj_consume_token(ID); jj_consume_token(EQUALS); token_source.SwitchTo(token_source.NAMED_PARAMETER_EXPRESSION); token_source.inInvocation = true; exp = Expression(); result.put(t.image, exp); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: ; break; default: jj_la1[57] = jj_gen; break label_13; } } token_source.inInvocation = false; {if (true) return result;} throw new Error("Missing return statement in function"); } final public ArrayList PositionalArgs() throws ParseException { ArrayList result = new ArrayList(); Expression arg; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case STRING_LITERAL: case RAW_STRING: case FALSE: case TRUE: case INTEGER: case DECIMAL: case DOT: case PLUS: case MINUS: case EXCLAM: case OPEN_BRACKET: case OPEN_PAREN: case OPEN_BRACE: case ID: arg = Expression(); result.add(arg); label_14: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case STRING_LITERAL: case RAW_STRING: case FALSE: case TRUE: case INTEGER: case DECIMAL: case DOT: case PLUS: case MINUS: case EXCLAM: case COMMA: case OPEN_BRACKET: case OPEN_PAREN: case OPEN_BRACE: case ID: ; break; default: jj_la1[58] = jj_gen; break label_14; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: jj_consume_token(COMMA); break; default: jj_la1[59] = jj_gen; ; } arg = Expression(); result.add(arg); } break; default: jj_la1[60] = jj_gen; ; } {if (true) return result;} throw new Error("Missing return statement in function"); } final public Comment Comment() throws ParseException { Token start, end; StringBuffer buf = new StringBuffer(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMENT: start = jj_consume_token(COMMENT); break; case TERSE_COMMENT: start = jj_consume_token(TERSE_COMMENT); break; default: jj_la1[61] = jj_gen; jj_consume_token(-1); throw new ParseException(); } end = UnparsedContent(buf); Comment result = new Comment(buf.toString()); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TextBlock NoParse() throws ParseException { Token start, end; StringBuffer buf = new StringBuffer(); start = jj_consume_token(NOPARSE); end = UnparsedContent(buf); TextBlock result = new TextBlock(buf.toString(), true); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public TransformBlock Transform() throws ParseException { Token start, end, argName; Expression exp, argExp; TemplateElement content = null; HashMap args = null; start = jj_consume_token(TRANSFORM); exp = Expression(); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case SEMICOLON: jj_consume_token(SEMICOLON); break; default: jj_la1[62] = jj_gen; ; } label_15: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: ; break; default: jj_la1[63] = jj_gen; break label_15; } argName = jj_consume_token(ID); jj_consume_token(EQUALS); argExp = Expression(); if (args == null) args = new HashMap(); args.put(argName.image, argExp); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case EMPTY_DIRECTIVE_END: end = jj_consume_token(EMPTY_DIRECTIVE_END); break; case DIRECTIVE_END: jj_consume_token(DIRECTIVE_END); content = OptionalBlock(); end = jj_consume_token(END_TRANSFORM); break; default: jj_la1[64] = jj_gen; jj_consume_token(-1); throw new ParseException(); } TransformBlock result = new TransformBlock(exp, args, content); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public SwitchBlock Switch() throws ParseException { SwitchBlock switchBlock; Case caseIns; Expression switchExp; Token start, end; boolean defaultFound = false; start = jj_consume_token(SWITCH); switchExp = Expression(); jj_consume_token(DIRECTIVE_END); ++switchNesting; switchBlock = new SwitchBlock(switchExp); label_16: while (true) { if (jj_2_15(2)) { ; } else { break label_16; } caseIns = Case(); if (caseIns.isDefault) { if (defaultFound) { String msg = getErrorStart(start) + "\nYou can only have one default case in a switch statement"; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } defaultFound = true; } switchBlock.addCase(caseIns); } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: jj_consume_token(WHITESPACE); break; default: jj_la1[65] = jj_gen; ; } end = jj_consume_token(END_SWITCH); --switchNesting; switchBlock.setLocation(template, start, end); {if (true) return switchBlock;} throw new Error("Missing return statement in function"); } final public Case Case() throws ParseException { Expression exp = null; TemplateElement block; boolean isDefault = false; Token start; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: jj_consume_token(WHITESPACE); break; default: jj_la1[66] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case CASE: start = jj_consume_token(CASE); exp = Expression(); jj_consume_token(DIRECTIVE_END); break; case DEFAUL: start = jj_consume_token(DEFAUL); isDefault = true; break; default: jj_la1[67] = jj_gen; jj_consume_token(-1); throw new ParseException(); } block = OptionalBlock(); Case result = new Case(exp, block, isDefault); result.setLocation(template, start, block); {if (true) return result;} throw new Error("Missing return statement in function"); } final public EscapeBlock Escape() throws ParseException { Token variable, start, end; Expression escapeExpr; TemplateElement content; start = jj_consume_token(ESCAPE); variable = jj_consume_token(ID); jj_consume_token(AS); escapeExpr = Expression(); jj_consume_token(DIRECTIVE_END); EscapeBlock result = new EscapeBlock(variable.image, escapeExpr, escapedExpression(escapeExpr)); escapes.addFirst(result); content = OptionalBlock(); result.setContent(content); escapes.removeFirst(); end = jj_consume_token(END_ESCAPE); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } final public NoEscapeBlock NoEscape() throws ParseException { Token start, end; TemplateElement content; start = jj_consume_token(NOESCAPE); if(escapes.isEmpty()) { String msg = getErrorStart(start) + "\nnoescape with no matching escape encountered."; {if (true) throw new ParseException(msg, start.beginLine, start.beginColumn);} } Object escape = escapes.removeFirst(); content = OptionalBlock(); end = jj_consume_token(END_NOESCAPE); escapes.addFirst(escape); NoEscapeBlock result = new NoEscapeBlock(content); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * Production to terminate potentially empty elements. Either a ">" or "/>" */ final public Token LooseDirectiveEnd() throws ParseException { Token t; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case DIRECTIVE_END: t = jj_consume_token(DIRECTIVE_END); break; case EMPTY_DIRECTIVE_END: t = jj_consume_token(EMPTY_DIRECTIVE_END); break; default: jj_la1[68] = jj_gen; jj_consume_token(-1); throw new ParseException(); } {if (true) return t;} throw new Error("Missing return statement in function"); } final public PropertySetting Setting() throws ParseException { Token start, end, key; Expression value; start = jj_consume_token(SETTING); key = jj_consume_token(ID); jj_consume_token(EQUALS); value = Expression(); end = LooseDirectiveEnd(); PropertySetting result = new PropertySetting(key.image, value); result.setLocation(template, start, end); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * A production for FreeMarker directives. */ final public TemplateElement FreemarkerDirective() throws ParseException { TemplateElement tp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case IF: tp = If(); break; case LIST: tp = List(); break; case FOREACH: tp = ForEach(); break; case ASSIGN: case GLOBALASSIGN: case LOCALASSIGN: tp = Assign(); break; case _INCLUDE: tp = Include(); break; case IMPORT: tp = Import(); break; case FUNCTION: case MACRO: tp = Macro(); break; case COMPRESS: tp = Compress(); break; case UNIFIED_CALL: tp = UnifiedMacroTransform(); break; case CALL: tp = Call(); break; case COMMENT: case TERSE_COMMENT: tp = Comment(); break; case NOPARSE: tp = NoParse(); break; case TRANSFORM: tp = Transform(); break; case SWITCH: tp = Switch(); break; case SETTING: tp = Setting(); break; case BREAK: tp = Break(); break; case RETURN: case SIMPLE_RETURN: tp = Return(); break; case STOP: case HALT: tp = Stop(); break; case FLUSH: tp = Flush(); break; case TRIM: case LTRIM: case RTRIM: case NOTRIM: tp = Trim(); break; case SIMPLE_NESTED: case NESTED: tp = Nested(); break; case ESCAPE: tp = Escape(); break; case NOESCAPE: tp = NoEscape(); break; case VISIT: tp = Visit(); break; case SIMPLE_RECURSE: case RECURSE: tp = Recurse(); break; case FALLBACK: tp = FallBack(); break; case ATTEMPT: tp = Attempt(); break; default: jj_la1[69] = jj_gen; jj_consume_token(-1); throw new ParseException(); } {if (true) return tp;} throw new Error("Missing return statement in function"); } /** * Production for a block of raw text * i.e. text that contains no * FreeMarker directives. */ final public TextBlock PCData() throws ParseException { StringBuffer buf = new StringBuffer(); Token t=null, start=null, prevToken = null; label_17: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: prevToken = t; t = jj_consume_token(WHITESPACE); break; case PRINTABLE_CHARS: t = jj_consume_token(PRINTABLE_CHARS); break; case FALSE_ALERT: t = jj_consume_token(FALSE_ALERT); break; default: jj_la1[70] = jj_gen; jj_consume_token(-1); throw new ParseException(); } buf.append(t.image); if (start == null) start = t; {if (prevToken != null) prevToken.next = null;} if (jj_2_16(2147483647)) { ; } else { break label_17; } } if (stripText && contentNesting == 1) {if (true) return TextBlock.EMPTY_BLOCK;} TextBlock result = new TextBlock(buf.toString(), false); result.setLocation(template, start, t); {if (true) return result;} throw new Error("Missing return statement in function"); } /** * Production for dealing with unparsed content, * i.e. what is inside a comment or noparse tag. * It returns the ending token. The content * of the tag is put in buf. */ final public Token UnparsedContent(StringBuffer buf) throws ParseException { Token t; label_18: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case KEEP_GOING: t = jj_consume_token(KEEP_GOING); break; case MAYBE_END: t = jj_consume_token(MAYBE_END); break; case TERSE_COMMENT_END: t = jj_consume_token(TERSE_COMMENT_END); break; case LONE_LESS_THAN_OR_DASH: t = jj_consume_token(LONE_LESS_THAN_OR_DASH); break; default: jj_la1[71] = jj_gen; jj_consume_token(-1); throw new ParseException(); } buf.append(t.image); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TERSE_COMMENT_END: case MAYBE_END: case KEEP_GOING: case LONE_LESS_THAN_OR_DASH: ; break; default: jj_la1[72] = jj_gen; break label_18; } } buf.setLength(buf.length() - t.image.length()); {if (true) return t;} throw new Error("Missing return statement in function"); } final public TemplateElement Content() throws ParseException { MixedContent nodes = new MixedContent(); TemplateElement elem, begin=null; contentNesting++; label_19: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: case PRINTABLE_CHARS: case FALSE_ALERT: elem = PCData(); break; case OUTPUT_ESCAPE: elem = StringOutput(); break; case NUMERICAL_ESCAPE: elem = NumericalOutput(); break; case ATTEMPT: case IF: case LIST: case FOREACH: case SWITCH: case ASSIGN: case GLOBALASSIGN: case LOCALASSIGN: case _INCLUDE: case IMPORT: case FUNCTION: case MACRO: case TRANSFORM: case VISIT: case STOP: case RETURN: case CALL: case SETTING: case COMPRESS: case COMMENT: case TERSE_COMMENT: case NOPARSE: case BREAK: case SIMPLE_RETURN: case HALT: case FLUSH: case TRIM: case LTRIM: case RTRIM: case NOTRIM: case SIMPLE_NESTED: case NESTED: case SIMPLE_RECURSE: case RECURSE: case FALLBACK: case ESCAPE: case NOESCAPE: case UNIFIED_CALL: elem = FreemarkerDirective(); break; default: jj_la1[73] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (begin == null) { begin = elem; } nodes.addElement(elem); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ATTEMPT: case IF: case LIST: case FOREACH: case SWITCH: case ASSIGN: case GLOBALASSIGN: case LOCALASSIGN: case _INCLUDE: case IMPORT: case FUNCTION: case MACRO: case TRANSFORM: case VISIT: case STOP: case RETURN: case CALL: case SETTING: case COMPRESS: case COMMENT: case TERSE_COMMENT: case NOPARSE: case BREAK: case SIMPLE_RETURN: case HALT: case FLUSH: case TRIM: case LTRIM: case RTRIM: case NOTRIM: case SIMPLE_NESTED: case NESTED: case SIMPLE_RECURSE: case RECURSE: case FALLBACK: case ESCAPE: case NOESCAPE: case UNIFIED_CALL: case WHITESPACE: case PRINTABLE_CHARS: case FALSE_ALERT: case OUTPUT_ESCAPE: case NUMERICAL_ESCAPE: ; break; default: jj_la1[74] = jj_gen; break label_19; } } contentNesting--; nodes.setLocation(template, begin, elem); {if (true) return nodes;} throw new Error("Missing return statement in function"); } /** * A production freemarker text that may contain * ${...} and #{...} but no directives. */ final public TemplateElement FreeMarkerText() throws ParseException { MixedContent nodes = new MixedContent(); TemplateElement elem, begin = null; label_20: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: case PRINTABLE_CHARS: case FALSE_ALERT: elem = PCData(); break; case OUTPUT_ESCAPE: elem = StringOutput(); break; case NUMERICAL_ESCAPE: elem = NumericalOutput(); break; default: jj_la1[75] = jj_gen; jj_consume_token(-1); throw new ParseException(); } if (begin == null) { begin = elem; } nodes.addElement(elem); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: case PRINTABLE_CHARS: case FALSE_ALERT: case OUTPUT_ESCAPE: case NUMERICAL_ESCAPE: ; break; default: jj_la1[76] = jj_gen; break label_20; } } nodes.setLocation(template, begin, elem); {if (true) return nodes;} throw new Error("Missing return statement in function"); } /** * A production for a block of optional content. * Returns an empty Text block if there is no * content. */ final public TemplateElement OptionalBlock() throws ParseException { TemplateElement tp = TextBlock.EMPTY_BLOCK; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ATTEMPT: case IF: case LIST: case FOREACH: case SWITCH: case ASSIGN: case GLOBALASSIGN: case LOCALASSIGN: case _INCLUDE: case IMPORT: case FUNCTION: case MACRO: case TRANSFORM: case VISIT: case STOP: case RETURN: case CALL: case SETTING: case COMPRESS: case COMMENT: case TERSE_COMMENT: case NOPARSE: case BREAK: case SIMPLE_RETURN: case HALT: case FLUSH: case TRIM: case LTRIM: case RTRIM: case NOTRIM: case SIMPLE_NESTED: case NESTED: case SIMPLE_RECURSE: case RECURSE: case FALLBACK: case ESCAPE: case NOESCAPE: case UNIFIED_CALL: case WHITESPACE: case PRINTABLE_CHARS: case FALSE_ALERT: case OUTPUT_ESCAPE: case NUMERICAL_ESCAPE: // has no effect but to get rid of a spurious warning. tp = Content(); break; default: jj_la1[77] = jj_gen; ; } {if (true) return tp;} throw new Error("Missing return statement in function"); } final public void HeaderElement() throws ParseException { Token key; Expression exp = null; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case WHITESPACE: jj_consume_token(WHITESPACE); break; default: jj_la1[78] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case TRIVIAL_FTL_HEADER: jj_consume_token(TRIVIAL_FTL_HEADER); break; case FTL_HEADER: jj_consume_token(FTL_HEADER); label_21: while (true) { switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: ; break; default: jj_la1[79] = jj_gen; break label_21; } key = jj_consume_token(ID); jj_consume_token(EQUALS); exp = Expression(); String ks = key.image; TemplateModel value = null; try { value = exp.getAsTemplateModel(null); } catch (Exception e) { {if (true) throw new ParseException("Could not evaluate expression: " + exp.getCanonicalForm() + " " + exp.getStartLocation() + "\nUnderlying cause: " + e.getMessage(), exp);} } String vs = null; if (value instanceof TemplateScalarModel) { try { vs = ((TemplateScalarModel) exp).getAsString(); } catch (TemplateModelException tme) {} } if (template != null) { if (ks.equalsIgnoreCase("encoding")) { if (vs == null) { {if (true) throw new ParseException("expecting encoding string here: " + exp.getStartLocation(), exp);} } String encoding = template.getEncoding(); if (encoding != null && !encoding.equals(vs)) { {if (true) throw new Template.WrongEncodingException(vs);} } } else if (ks.equalsIgnoreCase("STRIP_WHITESPACE")) { this.stripWhitespace = getBoolean(exp); } else if (ks.equalsIgnoreCase("STRIP_TEXT")) { this.stripText = getBoolean(exp); } else if (ks.equalsIgnoreCase("STRICT_SYNTAX")) { this.token_source.strictEscapeSyntax = getBoolean(exp); } else if (ks.equalsIgnoreCase("ns_prefixes")) { if (!(value instanceof TemplateHashModelEx)) { {if (true) throw new ParseException("Expecting a hash of prefixes to namespace URI's here. " + exp.getStartLocation(), exp);} } TemplateHashModelEx prefixMap = (TemplateHashModelEx) value; try { TemplateCollectionModel keys = prefixMap.keys(); for (TemplateModelIterator it = keys.iterator(); it.hasNext();) { String prefix = ((TemplateScalarModel) it.next()).getAsString(); TemplateModel valueModel = prefixMap.get(prefix); if (!(valueModel instanceof TemplateScalarModel)) { {if (true) throw new ParseException("Non-string value in prefix to namespace hash. " + exp.getStartLocation(), exp);} } String nsURI = ((TemplateScalarModel) valueModel).getAsString(); try { template.addPrefixNSMapping(prefix, nsURI); } catch (IllegalArgumentException iae) { {if (true) throw new ParseException(iae.getMessage() + " " + exp.getStartLocation(), exp);} } } } catch (TemplateModelException tme) { } } else if (ks.equalsIgnoreCase("attributes")) { if (!(value instanceof TemplateHashModelEx)) { {if (true) throw new ParseException("Expecting a hash of attribute names to values here. " + exp.getStartLocation(), exp);} } TemplateHashModelEx attributeMap = (TemplateHashModelEx) value; try { TemplateCollectionModel keys = attributeMap.keys(); for (TemplateModelIterator it = keys.iterator(); it.hasNext();) { String attName = ((TemplateScalarModel) it.next()).getAsString(); Object attValue = DeepUnwrap.unwrap(attributeMap.get(attName)); template.setCustomAttribute(attName, attValue); } } catch (TemplateModelException tme) { } } else { {if (true) throw new ParseException("Unknown FTL header parameter: " + key.image, key.beginLine, key.beginColumn);} } } } LooseDirectiveEnd(); break; default: jj_la1[80] = jj_gen; jj_consume_token(-1); throw new ParseException(); } } final public Map ParamList() throws ParseException { Identifier id; Expression exp; Map result = new HashMap(); label_22: while (true) { id = Identifier(); jj_consume_token(EQUALS); exp = Expression(); result.put(id.toString(), exp); switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case COMMA: jj_consume_token(COMMA); break; default: jj_la1[81] = jj_gen; ; } switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { case ID: ; break; default: jj_la1[82] = jj_gen; break label_22; } } {if (true) return result;} throw new Error("Missing return statement in function"); } /** * Root production to be used when parsing * an entire file. */ final public TemplateElement Root() throws ParseException { TemplateElement doc; if (jj_2_17(2147483647)) { HeaderElement(); } else { ; } doc = OptionalBlock(); jj_consume_token(0); doc.setParentRecursively(null); {if (true) return doc.postParseCleanup(stripWhitespace);} throw new Error("Missing return statement in function"); } final private boolean jj_2_1(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_1(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(0, xla); } } final private boolean jj_2_2(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_2(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(1, xla); } } final private boolean jj_2_3(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_3(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(2, xla); } } final private boolean jj_2_4(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_4(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(3, xla); } } final private boolean jj_2_5(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_5(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(4, xla); } } final private boolean jj_2_6(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_6(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(5, xla); } } final private boolean jj_2_7(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_7(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(6, xla); } } final private boolean jj_2_8(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_8(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(7, xla); } } final private boolean jj_2_9(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_9(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(8, xla); } } final private boolean jj_2_10(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_10(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(9, xla); } } final private boolean jj_2_11(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_11(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(10, xla); } } final private boolean jj_2_12(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_12(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(11, xla); } } final private boolean jj_2_13(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_13(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(12, xla); } } final private boolean jj_2_14(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_14(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(13, xla); } } final private boolean jj_2_15(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_15(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(14, xla); } } final private boolean jj_2_16(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_16(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(15, xla); } } final private boolean jj_2_17(int xla) { jj_la = xla; jj_lastpos = jj_scanpos = token; try { return !jj_3_17(); } catch(LookaheadSuccess ls) { return true; } finally { jj_save(16, xla); } } final private boolean jj_3R_32() { if (jj_3R_35()) return true; Token xsp; xsp = jj_scanpos; if (jj_3R_36()) jj_scanpos = xsp; return false; } final private boolean jj_3R_110() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(56)) { jj_scanpos = xsp; if (jj_3R_132()) return true; } return false; } final private boolean jj_3R_108() { if (jj_scan_token(NOESCAPE)) return true; return false; } final private boolean jj_3R_170() { if (jj_scan_token(OPEN_BRACKET)) return true; if (jj_3R_23()) return true; if (jj_scan_token(CLOSE_BRACKET)) return true; return false; } final private boolean jj_3R_122() { if (jj_scan_token(FUNCTION)) return true; return false; } final private boolean jj_3_3() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(100)) { jj_scanpos = xsp; if (jj_scan_token(103)) { jj_scanpos = xsp; if (jj_scan_token(104)) return true; } } return false; } final private boolean jj_3R_118() { if (jj_scan_token(PERCENT)) return true; return false; } final private boolean jj_3R_92() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(20)) { jj_scanpos = xsp; if (jj_3R_122()) return true; } return false; } final private boolean jj_3R_117() { if (jj_scan_token(DIVIDE)) return true; return false; } final private boolean jj_3R_109() { if (jj_scan_token(VISIT)) return true; return false; } final private boolean jj_3R_116() { if (jj_scan_token(TIMES)) return true; return false; } final private boolean jj_3R_82() { Token xsp; xsp = jj_scanpos; if (jj_3R_116()) { jj_scanpos = xsp; if (jj_3R_117()) { jj_scanpos = xsp; if (jj_3R_118()) return true; } } if (jj_3R_81()) return true; return false; } final private boolean jj_3R_107() { if (jj_scan_token(ESCAPE)) return true; return false; } final private boolean jj_3R_50() { if (jj_3R_81()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_82()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_88() { if (jj_scan_token(FOREACH)) return true; return false; } final private boolean jj_3R_176() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(94)) { jj_scanpos = xsp; if (jj_scan_token(95)) { jj_scanpos = xsp; if (jj_scan_token(96)) { jj_scanpos = xsp; if (jj_scan_token(97)) { jj_scanpos = xsp; if (jj_scan_token(83)) { jj_scanpos = xsp; if (jj_scan_token(84)) { jj_scanpos = xsp; if (jj_scan_token(117)) { jj_scanpos = xsp; if (jj_scan_token(118)) { jj_scanpos = xsp; if (jj_scan_token(119)) return true; } } } } } } } } return false; } final private boolean jj_3R_27() { if (jj_scan_token(DEFAUL)) return true; return false; } final private boolean jj_3R_26() { if (jj_scan_token(CASE)) return true; if (jj_3R_23()) return true; return false; } final private boolean jj_3R_91() { if (jj_scan_token(IMPORT)) return true; return false; } final private boolean jj_3R_169() { if (jj_scan_token(DOT)) return true; Token xsp; xsp = jj_scanpos; if (jj_scan_token(120)) { jj_scanpos = xsp; if (jj_scan_token(100)) { jj_scanpos = xsp; if (jj_scan_token(101)) { jj_scanpos = xsp; if (jj_3R_176()) return true; } } } return false; } final private boolean jj_3R_24() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(68)) jj_scanpos = xsp; xsp = jj_scanpos; if (jj_3R_26()) { jj_scanpos = xsp; if (jj_3R_27()) return true; } if (jj_3R_28()) return true; return false; } final private boolean jj_3_2() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(98)) { jj_scanpos = xsp; if (jj_scan_token(99)) return true; } return false; } final private boolean jj_3R_84() { if (jj_scan_token(MINUS)) return true; return false; } final private boolean jj_3R_83() { if (jj_scan_token(PLUS)) return true; return false; } final private boolean jj_3R_87() { if (jj_scan_token(LIST)) return true; return false; } final private boolean jj_3R_51() { Token xsp; xsp = jj_scanpos; if (jj_3R_83()) { jj_scanpos = xsp; if (jj_3R_84()) return true; } if (jj_3R_50()) return true; return false; } final private boolean jj_3R_44() { if (jj_3R_50()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_51()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_172() { if (jj_scan_token(BUILT_IN)) return true; if (jj_scan_token(ID)) return true; return false; } final private boolean jj_3_15() { if (jj_3R_24()) return true; return false; } final private boolean jj_3R_90() { if (jj_scan_token(_INCLUDE)) return true; return false; } final private boolean jj_3R_136() { if (jj_scan_token(MINUS)) return true; return false; } final private boolean jj_3R_99() { if (jj_scan_token(SWITCH)) return true; return false; } final private boolean jj_3R_174() { if (jj_scan_token(EXISTS)) return true; return false; } final private boolean jj_3R_133() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(98)) { jj_scanpos = xsp; if (jj_3R_136()) return true; } if (jj_3R_135()) return true; return false; } final private boolean jj_3_10() { if (jj_3R_23()) return true; return false; } final private boolean jj_3R_112() { if (jj_scan_token(ATTEMPT)) return true; return false; } final private boolean jj_3R_178() { if (jj_3R_23()) return true; return false; } final private boolean jj_3R_137() { if (jj_scan_token(EXCLAM)) return true; return false; } final private boolean jj_3R_177() { if (jj_scan_token(EXCLAM)) return true; Token xsp; xsp = jj_scanpos; if (jj_3R_178()) jj_scanpos = xsp; return false; } final private boolean jj_3R_134() { Token xsp; if (jj_3R_137()) return true; while (true) { xsp = jj_scanpos; if (jj_3R_137()) { jj_scanpos = xsp; break; } } if (jj_3R_135()) return true; return false; } final private boolean jj_3R_173() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(128)) { jj_scanpos = xsp; if (jj_3R_177()) return true; } return false; } final private boolean jj_3R_98() { if (jj_scan_token(TRANSFORM)) return true; return false; } final private boolean jj_3R_31() { if (jj_3R_34()) return true; return false; } final private boolean jj_3_11() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(108)) jj_scanpos = xsp; xsp = jj_scanpos; if (jj_scan_token(120)) { jj_scanpos = xsp; if (jj_scan_token(81)) return true; } if (jj_scan_token(EQUALS)) return true; return false; } final private boolean jj_3R_28() { Token xsp; xsp = jj_scanpos; if (jj_3R_31()) jj_scanpos = xsp; return false; } final private boolean jj_3R_166() { if (jj_3R_174()) return true; return false; } final private boolean jj_3R_165() { if (jj_3R_173()) return true; return false; } final private boolean jj_3R_164() { if (jj_3R_172()) return true; return false; } final private boolean jj_3R_163() { if (jj_3R_171()) return true; return false; } final private boolean jj_3R_162() { if (jj_3R_170()) return true; return false; } final private boolean jj_3R_161() { if (jj_3R_169()) return true; return false; } final private boolean jj_3R_97() { if (jj_scan_token(NOPARSE)) return true; return false; } final private boolean jj_3R_155() { Token xsp; xsp = jj_scanpos; if (jj_3R_161()) { jj_scanpos = xsp; if (jj_3R_162()) { jj_scanpos = xsp; if (jj_3R_163()) { jj_scanpos = xsp; if (jj_3R_164()) { jj_scanpos = xsp; if (jj_3R_165()) { jj_scanpos = xsp; if (jj_3R_166()) return true; } } } } } return false; } final private boolean jj_3R_86() { if (jj_scan_token(IF)) return true; return false; } final private boolean jj_3R_115() { if (jj_3R_135()) return true; return false; } final private boolean jj_3R_114() { if (jj_3R_134()) return true; return false; } final private boolean jj_3R_113() { if (jj_3R_133()) return true; return false; } final private boolean jj_3R_81() { Token xsp; xsp = jj_scanpos; if (jj_3R_113()) { jj_scanpos = xsp; if (jj_3R_114()) { jj_scanpos = xsp; if (jj_3R_115()) return true; } } return false; } final private boolean jj_3R_96() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(28)) { jj_scanpos = xsp; if (jj_scan_token(29)) return true; } return false; } final private boolean jj_3R_121() { if (jj_scan_token(LOCALASSIGN)) return true; return false; } final private boolean jj_3R_120() { if (jj_scan_token(GLOBALASSIGN)) return true; return false; } final private boolean jj_3R_119() { if (jj_scan_token(ASSIGN)) return true; return false; } final private boolean jj_3R_154() { if (jj_scan_token(DOT)) return true; if (jj_scan_token(ID)) return true; return false; } final private boolean jj_3R_89() { Token xsp; xsp = jj_scanpos; if (jj_3R_119()) { jj_scanpos = xsp; if (jj_3R_120()) { jj_scanpos = xsp; if (jj_3R_121()) return true; } } return false; } final private boolean jj_3R_175() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(108)) jj_scanpos = xsp; if (jj_3R_23()) return true; return false; } final private boolean jj_3R_168() { if (jj_3R_23()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_175()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_153() { if (jj_scan_token(OPEN_PAREN)) return true; if (jj_3R_23()) return true; if (jj_scan_token(CLOSE_PAREN)) return true; return false; } final private boolean jj_3R_160() { Token xsp; xsp = jj_scanpos; if (jj_3R_168()) jj_scanpos = xsp; return false; } final private boolean jj_3R_43() { if (jj_3R_49()) return true; return false; } final private boolean jj_3R_42() { if (jj_3R_48()) return true; return false; } final private boolean jj_3_1() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(87)) { jj_scanpos = xsp; if (jj_scan_token(111)) { jj_scanpos = xsp; if (jj_scan_token(113)) { jj_scanpos = xsp; if (jj_scan_token(89)) { jj_scanpos = xsp; if (jj_scan_token(107)) { jj_scanpos = xsp; if (jj_scan_token(128)) { jj_scanpos = xsp; if (jj_scan_token(90)) return true; } } } } } } return false; } final private boolean jj_3R_41() { if (jj_3R_47()) return true; return false; } final private boolean jj_3R_40() { if (jj_3R_46()) return true; return false; } final private boolean jj_3R_129() { if (jj_scan_token(NOTRIM)) return true; return false; } final private boolean jj_3R_37() { Token xsp; xsp = jj_scanpos; if (jj_3R_40()) { jj_scanpos = xsp; if (jj_3R_41()) { jj_scanpos = xsp; if (jj_3R_42()) { jj_scanpos = xsp; if (jj_3R_43()) return true; } } } return false; } final private boolean jj_3R_128() { if (jj_scan_token(RTRIM)) return true; return false; } final private boolean jj_3R_127() { if (jj_scan_token(LTRIM)) return true; return false; } final private boolean jj_3R_146() { if (jj_3R_155()) return true; return false; } final private boolean jj_3R_34() { Token xsp; if (jj_3R_37()) return true; while (true) { xsp = jj_scanpos; if (jj_3R_37()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_126() { if (jj_scan_token(TRIM)) return true; return false; } final private boolean jj_3R_152() { if (jj_scan_token(ID)) return true; return false; } final private boolean jj_3R_145() { if (jj_3R_154()) return true; return false; } final private boolean jj_3R_105() { Token xsp; xsp = jj_scanpos; if (jj_3R_126()) { jj_scanpos = xsp; if (jj_3R_127()) { jj_scanpos = xsp; if (jj_3R_128()) { jj_scanpos = xsp; if (jj_3R_129()) return true; } } } return false; } final private boolean jj_3R_144() { if (jj_3R_153()) return true; return false; } final private boolean jj_3R_143() { if (jj_3R_152()) return true; return false; } final private boolean jj_3R_142() { if (jj_3R_151()) return true; return false; } final private boolean jj_3R_141() { if (jj_3R_150()) return true; return false; } final private boolean jj_3R_140() { if (jj_3R_149()) return true; return false; } final private boolean jj_3R_139() { if (jj_3R_148()) return true; return false; } final private boolean jj_3R_138() { if (jj_3R_147()) return true; return false; } final private boolean jj_3R_104() { if (jj_scan_token(FLUSH)) return true; return false; } final private boolean jj_3_13() { if (jj_scan_token(OPEN_PAREN)) return true; return false; } final private boolean jj_3R_135() { Token xsp; xsp = jj_scanpos; if (jj_3R_138()) { jj_scanpos = xsp; if (jj_3R_139()) { jj_scanpos = xsp; if (jj_3R_140()) { jj_scanpos = xsp; if (jj_3R_141()) { jj_scanpos = xsp; if (jj_3R_142()) { jj_scanpos = xsp; if (jj_3R_143()) { jj_scanpos = xsp; if (jj_3R_144()) { jj_scanpos = xsp; if (jj_3R_145()) return true; } } } } } } } while (true) { xsp = jj_scanpos; if (jj_3R_146()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_147() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(85)) { jj_scanpos = xsp; if (jj_scan_token(86)) return true; } return false; } final private boolean jj_3_14() { if (jj_scan_token(ID)) return true; if (jj_scan_token(EQUALS)) return true; return false; } final private boolean jj_3R_151() { if (jj_scan_token(OPEN_BRACKET)) return true; if (jj_3R_160()) return true; if (jj_scan_token(CLOSE_BRACKET)) return true; return false; } final private boolean jj_3R_23() { if (jj_3R_25()) return true; return false; } final private boolean jj_3R_131() { if (jj_scan_token(NESTED)) return true; return false; } final private boolean jj_3_16() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(68)) { jj_scanpos = xsp; if (jj_scan_token(69)) { jj_scanpos = xsp; if (jj_scan_token(70)) return true; } } return false; } final private boolean jj_3R_48() { if (jj_scan_token(NUMERICAL_ESCAPE)) return true; return false; } final private boolean jj_3R_95() { if (jj_scan_token(CALL)) return true; return false; } final private boolean jj_3_9() { if (jj_scan_token(OR)) return true; return false; } final private boolean jj_3R_85() { if (jj_scan_token(WHITESPACE)) return true; return false; } final private boolean jj_3R_130() { if (jj_scan_token(SIMPLE_NESTED)) return true; return false; } final private boolean jj_3R_53() { Token xsp; xsp = jj_scanpos; if (jj_3R_85()) { jj_scanpos = xsp; if (jj_scan_token(69)) { jj_scanpos = xsp; if (jj_scan_token(70)) return true; } } return false; } final private boolean jj_3R_106() { Token xsp; xsp = jj_scanpos; if (jj_3R_130()) { jj_scanpos = xsp; if (jj_3R_131()) return true; } return false; } final private boolean jj_3R_46() { Token xsp; if (jj_3R_53()) return true; while (true) { xsp = jj_scanpos; if (jj_3R_53()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_30() { if (jj_scan_token(OR)) return true; if (jj_3R_29()) return true; return false; } final private boolean jj_3R_25() { if (jj_3R_29()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_30()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_47() { if (jj_scan_token(OUTPUT_ESCAPE)) return true; return false; } final private boolean jj_3R_125() { if (jj_scan_token(STOP)) return true; return false; } final private boolean jj_3_8() { if (jj_scan_token(AND)) return true; return false; } final private boolean jj_3R_103() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(47)) { jj_scanpos = xsp; if (jj_3R_125()) return true; } return false; } final private boolean jj_3R_80() { if (jj_3R_112()) return true; return false; } final private boolean jj_3R_79() { if (jj_3R_111()) return true; return false; } final private boolean jj_3R_78() { if (jj_3R_110()) return true; return false; } final private boolean jj_3R_33() { if (jj_scan_token(AND)) return true; if (jj_3R_32()) return true; return false; } final private boolean jj_3R_77() { if (jj_3R_109()) return true; return false; } final private boolean jj_3R_76() { if (jj_3R_108()) return true; return false; } final private boolean jj_3R_75() { if (jj_3R_107()) return true; return false; } final private boolean jj_3R_29() { if (jj_3R_32()) return true; Token xsp; while (true) { xsp = jj_scanpos; if (jj_3R_33()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3_12() { if (jj_scan_token(ID)) return true; if (jj_scan_token(EQUALS)) return true; return false; } final private boolean jj_3R_74() { if (jj_3R_106()) return true; return false; } final private boolean jj_3R_73() { if (jj_3R_105()) return true; return false; } final private boolean jj_3R_167() { if (jj_scan_token(COMMA)) return true; if (jj_3R_23()) return true; Token xsp; xsp = jj_scanpos; if (jj_scan_token(108)) { jj_scanpos = xsp; if (jj_scan_token(110)) return true; } if (jj_3R_23()) return true; return false; } final private boolean jj_3R_72() { if (jj_3R_104()) return true; return false; } final private boolean jj_3R_71() { if (jj_3R_103()) return true; return false; } final private boolean jj_3R_70() { if (jj_3R_102()) return true; return false; } final private boolean jj_3R_69() { if (jj_3R_101()) return true; return false; } final private boolean jj_3R_68() { if (jj_3R_100()) return true; return false; } final private boolean jj_3_6() { if (jj_3R_23()) return true; return false; } final private boolean jj_3R_67() { if (jj_3R_99()) return true; return false; } final private boolean jj_3R_156() { if (jj_3R_23()) return true; Token xsp; xsp = jj_scanpos; if (jj_scan_token(108)) { jj_scanpos = xsp; if (jj_scan_token(110)) return true; } if (jj_3R_23()) return true; while (true) { xsp = jj_scanpos; if (jj_3R_167()) { jj_scanpos = xsp; break; } } return false; } final private boolean jj_3R_66() { if (jj_3R_98()) return true; return false; } final private boolean jj_3R_65() { if (jj_3R_97()) return true; return false; } final private boolean jj_3_7() { if (jj_scan_token(DOT_DOT)) return true; return false; } final private boolean jj_3R_64() { if (jj_3R_96()) return true; return false; } final private boolean jj_3R_148() { if (jj_scan_token(OPEN_BRACE)) return true; Token xsp; xsp = jj_scanpos; if (jj_3R_156()) jj_scanpos = xsp; if (jj_scan_token(CLOSE_BRACE)) return true; return false; } final private boolean jj_3R_124() { if (jj_scan_token(RETURN)) return true; return false; } final private boolean jj_3R_94() { if (jj_scan_token(UNIFIED_CALL)) return true; return false; } final private boolean jj_3R_63() { if (jj_3R_95()) return true; return false; } final private boolean jj_3R_123() { if (jj_scan_token(SIMPLE_RETURN)) return true; return false; } final private boolean jj_3R_52() { if (jj_3R_44()) return true; return false; } final private boolean jj_3R_62() { if (jj_3R_94()) return true; return false; } final private boolean jj_3R_61() { if (jj_3R_93()) return true; return false; } final private boolean jj_3R_102() { Token xsp; xsp = jj_scanpos; if (jj_3R_123()) { jj_scanpos = xsp; if (jj_3R_124()) return true; } return false; } final private boolean jj_3R_60() { if (jj_3R_92()) return true; return false; } final private boolean jj_3R_45() { if (jj_scan_token(DOT_DOT)) return true; Token xsp; xsp = jj_scanpos; if (jj_3R_52()) jj_scanpos = xsp; return false; } final private boolean jj_3R_59() { if (jj_3R_91()) return true; return false; } final private boolean jj_3R_58() { if (jj_3R_90()) return true; return false; } final private boolean jj_3R_38() { if (jj_3R_44()) return true; Token xsp; xsp = jj_scanpos; if (jj_3R_45()) jj_scanpos = xsp; return false; } final private boolean jj_3R_159() { if (jj_scan_token(TRUE)) return true; return false; } final private boolean jj_3R_57() { if (jj_3R_89()) return true; return false; } final private boolean jj_3R_158() { if (jj_scan_token(FALSE)) return true; return false; } final private boolean jj_3R_56() { if (jj_3R_88()) return true; return false; } final private boolean jj_3R_55() { if (jj_3R_87()) return true; return false; } final private boolean jj_3R_54() { if (jj_3R_86()) return true; return false; } final private boolean jj_3R_150() { Token xsp; xsp = jj_scanpos; if (jj_3R_158()) { jj_scanpos = xsp; if (jj_3R_159()) return true; } return false; } final private boolean jj_3R_93() { if (jj_scan_token(COMPRESS)) return true; return false; } final private boolean jj_3R_49() { Token xsp; xsp = jj_scanpos; if (jj_3R_54()) { jj_scanpos = xsp; if (jj_3R_55()) { jj_scanpos = xsp; if (jj_3R_56()) { jj_scanpos = xsp; if (jj_3R_57()) { jj_scanpos = xsp; if (jj_3R_58()) { jj_scanpos = xsp; if (jj_3R_59()) { jj_scanpos = xsp; if (jj_3R_60()) { jj_scanpos = xsp; if (jj_3R_61()) { jj_scanpos = xsp; if (jj_3R_62()) { jj_scanpos = xsp; if (jj_3R_63()) { jj_scanpos = xsp; if (jj_3R_64()) { jj_scanpos = xsp; if (jj_3R_65()) { jj_scanpos = xsp; if (jj_3R_66()) { jj_scanpos = xsp; if (jj_3R_67()) { jj_scanpos = xsp; if (jj_3R_68()) { jj_scanpos = xsp; if (jj_3R_69()) { jj_scanpos = xsp; if (jj_3R_70()) { jj_scanpos = xsp; if (jj_3R_71()) { jj_scanpos = xsp; if (jj_3R_72()) { jj_scanpos = xsp; if (jj_3R_73()) { jj_scanpos = xsp; if (jj_3R_74()) { jj_scanpos = xsp; if (jj_3R_75()) { jj_scanpos = xsp; if (jj_3R_76()) { jj_scanpos = xsp; if (jj_3R_77()) { jj_scanpos = xsp; if (jj_3R_78()) { jj_scanpos = xsp; if (jj_3R_79()) { jj_scanpos = xsp; if (jj_3R_80()) return true; } } } } } } } } } } } } } } } } } } } } } } } } } } return false; } final private boolean jj_3R_101() { if (jj_scan_token(BREAK)) return true; return false; } final private boolean jj_3_5() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(126)) { jj_scanpos = xsp; if (jj_scan_token(97)) { jj_scanpos = xsp; if (jj_scan_token(125)) { jj_scanpos = xsp; if (jj_scan_token(96)) { jj_scanpos = xsp; if (jj_scan_token(95)) { jj_scanpos = xsp; if (jj_scan_token(95)) { jj_scanpos = xsp; if (jj_scan_token(94)) return true; } } } } } } return false; } final private boolean jj_3R_100() { if (jj_scan_token(SETTING)) return true; return false; } final private boolean jj_3R_39() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(126)) { jj_scanpos = xsp; if (jj_scan_token(97)) { jj_scanpos = xsp; if (jj_scan_token(125)) { jj_scanpos = xsp; if (jj_scan_token(96)) { jj_scanpos = xsp; if (jj_scan_token(95)) { jj_scanpos = xsp; if (jj_scan_token(94)) return true; } } } } } if (jj_3R_38()) return true; return false; } final private boolean jj_3R_157() { if (jj_scan_token(RAW_STRING)) return true; return false; } final private boolean jj_3R_35() { if (jj_3R_38()) return true; Token xsp; xsp = jj_scanpos; if (jj_3R_39()) jj_scanpos = xsp; return false; } final private boolean jj_3R_111() { if (jj_scan_token(FALLBACK)) return true; return false; } final private boolean jj_3R_149() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(81)) { jj_scanpos = xsp; if (jj_3R_157()) return true; } return false; } final private boolean jj_3_17() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(68)) jj_scanpos = xsp; xsp = jj_scanpos; if (jj_scan_token(66)) { jj_scanpos = xsp; if (jj_scan_token(65)) return true; } return false; } final private boolean jj_3_4() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(93)) { jj_scanpos = xsp; if (jj_scan_token(91)) { jj_scanpos = xsp; if (jj_scan_token(92)) return true; } } return false; } final private boolean jj_3R_171() { if (jj_scan_token(OPEN_PAREN)) return true; if (jj_3R_160()) return true; if (jj_scan_token(CLOSE_PAREN)) return true; return false; } final private boolean jj_3R_36() { Token xsp; xsp = jj_scanpos; if (jj_scan_token(93)) { jj_scanpos = xsp; if (jj_scan_token(91)) { jj_scanpos = xsp; if (jj_scan_token(92)) return true; } } if (jj_3R_35()) return true; return false; } final private boolean jj_3R_132() { if (jj_scan_token(RECURSE)) return true; return false; } public FMParserTokenManager token_source; SimpleCharStream jj_input_stream; public Token token, jj_nt; private int jj_ntk; private Token jj_scanpos, jj_lastpos; private int jj_la; public boolean lookingAhead = false; private boolean jj_semLA; private int jj_gen; final private int[] jj_la1 = new int[83]; static private int[] jj_la1_0; static private int[] jj_la1_1; static private int[] jj_la1_2; static private int[] jj_la1_3; static private int[] jj_la1_4; static { jj_la1_0(); jj_la1_1(); jj_la1_2(); jj_la1_3(); jj_la1_4(); } private static void jj_la1_0() { jj_la1_0 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x800000,0x0,0x0,0x1c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x2000,0x0,0x7fffdd40,0x0,0x0,0x0,0x7fffdd40,0x7fffdd40,0x0,0x0,0x7fffdd40,0x0,0x0,0x0,0x0,0x0,}; } private static void jj_la1_1() { jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x6,0x0,0x0,0x0,0x3000000,0x4000,0x8000,0xc00000,0x1e0000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0xafdfe000,0x0,0x0,0x0,0xafdfe000,0xafdfe000,0x0,0x0,0xafdfe000,0x0,0x0,0x0,0x0,0x0,}; } private static void jj_la1_2() { jj_la1_2 = new int[] {0xfe0000,0xfe0000,0x0,0x0,0x0,0x0,0x38000000,0xc0000000,0x600000,0x60000,0x6800000,0x0,0xc0180000,0xc0180000,0x60000,0x180000,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,0x0,0xfe0000,0x0,0x0,0x0,0x0,0x10,0x10,0x0,0x0,0x0,0x70,0x0,0x0,0x1f0,0x1f0,0x1f0,0x1f0,0x1f0,0x10,0x0,0x6,0x0,0x0,}; } private static void jj_la1_3() { jj_la1_3 = new int[] {0x10a8000,0x10a880c,0x800,0xc,0xc,0x190,0x0,0x60000003,0x0,0x1000000,0x28800,0x800,0xe00003,0x1e00033,0x0,0x0,0x5000,0x1000,0x5000,0x10a880c,0x2000,0x0,0x0,0x0,0x800000,0x10a880c,0x800000,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x200000,0x200000,0x0,0x8200000,0x2000,0x1000000,0x0,0x20000,0x1000000,0x40,0x0,0x1000,0x40000,0x0,0x80000000,0x80000000,0x80001000,0x80000000,0x80000000,0x81000000,0x2000,0x18000000,0x40000,0x1000000,0x10a980c,0x1000,0x10a880c,0x0,0x2000,0x1000000,0x18000000,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x1000,0x1000000,}; } private static void jj_la1_4() { jj_la1_4 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e,0x1e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,}; } final private JJCalls[] jj_2_rtns = new JJCalls[17]; private boolean jj_rescan = false; private int jj_gc = 0; public FMParser(java.io.InputStream stream) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new FMParserTokenManager(jj_input_stream); token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 83; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } public void ReInit(java.io.InputStream stream) { jj_input_stream.ReInit(stream, 1, 1); token_source.ReInit(jj_input_stream); token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 83; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } public FMParser(java.io.Reader stream) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new FMParserTokenManager(jj_input_stream); token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 83; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } public void ReInit(java.io.Reader stream) { jj_input_stream.ReInit(stream, 1, 1); token_source.ReInit(jj_input_stream); token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 83; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } public FMParser(FMParserTokenManager tm) { token_source = tm; token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 83; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } public void ReInit(FMParserTokenManager tm) { token_source = tm; token = new Token(); jj_ntk = -1; jj_gen = 0; for (int i = 0; i < 83; i++) jj_la1[i] = -1; for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); } final private Token jj_consume_token(int kind) throws ParseException { Token oldToken; if ((oldToken = token).next != null) token = token.next; else token = token.next = token_source.getNextToken(); jj_ntk = -1; if (token.kind == kind) { jj_gen++; if (++jj_gc > 100) { jj_gc = 0; for (int i = 0; i < jj_2_rtns.length; i++) { JJCalls c = jj_2_rtns[i]; while (c != null) { if (c.gen < jj_gen) c.first = null; c = c.next; } } } return token; } token = oldToken; jj_kind = kind; throw generateParseException(); } static private final class LookaheadSuccess extends java.lang.Error { } final private LookaheadSuccess jj_ls = new LookaheadSuccess(); final private boolean jj_scan_token(int kind) { if (jj_scanpos == jj_lastpos) { jj_la--; if (jj_scanpos.next == null) { jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); } else { jj_lastpos = jj_scanpos = jj_scanpos.next; } } else { jj_scanpos = jj_scanpos.next; } if (jj_rescan) { int i = 0; Token tok = token; while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } if (tok != null) jj_add_error_token(kind, i); } if (jj_scanpos.kind != kind) return true; if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; return false; } final public Token getNextToken() { if (token.next != null) token = token.next; else token = token.next = token_source.getNextToken(); jj_ntk = -1; jj_gen++; return token; } final public Token getToken(int index) { Token t = lookingAhead ? jj_scanpos : token; for (int i = 0; i < index; i++) { if (t.next != null) t = t.next; else t = t.next = token_source.getNextToken(); } return t; } final private int jj_ntk() { if ((jj_nt=token.next) == null) return (jj_ntk = (token.next=token_source.getNextToken()).kind); else return (jj_ntk = jj_nt.kind); } private java.util.Vector jj_expentries = new java.util.Vector(); private int[] jj_expentry; private int jj_kind = -1; private int[] jj_lasttokens = new int[100]; private int jj_endpos; private void jj_add_error_token(int kind, int pos) { if (pos >= 100) return; if (pos == jj_endpos + 1) { jj_lasttokens[jj_endpos++] = kind; } else if (jj_endpos != 0) { jj_expentry = new int[jj_endpos]; for (int i = 0; i < jj_endpos; i++) { jj_expentry[i] = jj_lasttokens[i]; } boolean exists = false; for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) { int[] oldentry = (int[])(e.nextElement()); if (oldentry.length == jj_expentry.length) { exists = true; for (int i = 0; i < jj_expentry.length; i++) { if (oldentry[i] != jj_expentry[i]) { exists = false; break; } } if (exists) break; } } if (!exists) jj_expentries.addElement(jj_expentry); if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; } } public ParseException generateParseException() { jj_expentries.removeAllElements(); boolean[] la1tokens = new boolean[133]; for (int i = 0; i < 133; i++) { la1tokens[i] = false; } if (jj_kind >= 0) { la1tokens[jj_kind] = true; jj_kind = -1; } for (int i = 0; i < 83; i++) { if (jj_la1[i] == jj_gen) { for (int j = 0; j < 32; j++) { if ((jj_la1_0[i] & (1< jj_gen) { jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; switch (i) { case 0: jj_3_1(); break; case 1: jj_3_2(); break; case 2: jj_3_3(); break; case 3: jj_3_4(); break; case 4: jj_3_5(); break; case 5: jj_3_6(); break; case 6: jj_3_7(); break; case 7: jj_3_8(); break; case 8: jj_3_9(); break; case 9: jj_3_10(); break; case 10: jj_3_11(); break; case 11: jj_3_12(); break; case 12: jj_3_13(); break; case 13: jj_3_14(); break; case 14: jj_3_15(); break; case 15: jj_3_16(); break; case 16: jj_3_17(); break; } } p = p.next; } while (p != null); } jj_rescan = false; } final private void jj_save(int index, int xla) { JJCalls p = jj_2_rtns[index]; while (p.gen > jj_gen) { if (p.next == null) { p = p.next = new JJCalls(); break; } p = p.next; } p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; } static final class JJCalls { int gen; Token first; int arg; JJCalls next; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/SequenceBuiltins.java0000644000175000017500000010764611723544471025643 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.Serializable; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import freemarker.ext.beans.CollectionModel; import freemarker.template.SimpleNumber; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateException; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelListSequence; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModelIterator; import freemarker.template.utility.Constants; import freemarker.template.utility.StringUtil; /** * A holder for builtins that operate exclusively on TemplateSequenceModels. */ abstract class SequenceBuiltins { abstract static class SequenceBuiltIn extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (!(model instanceof TemplateSequenceModel)) { throw invalidTypeException(model, target, env, "sequence"); } return calculateResult((TemplateSequenceModel) model); } abstract TemplateModel calculateResult(TemplateSequenceModel tsm) throws TemplateModelException; } static class firstBI extends SequenceBuiltIn { TemplateModel calculateResult(TemplateSequenceModel tsm) throws TemplateModelException { if (tsm.size() == 0) { return null; } return tsm.get(0); } } static class lastBI extends SequenceBuiltIn { TemplateModel calculateResult(TemplateSequenceModel tsm) throws TemplateModelException { if (tsm.size() == 0) { return null; } return tsm.get(tsm.size() -1); } } static class reverseBI extends SequenceBuiltIn { TemplateModel calculateResult(TemplateSequenceModel tsm) { if (tsm instanceof ReverseSequence) { return ((ReverseSequence) tsm).seq; } else { return new ReverseSequence(tsm); } } private static class ReverseSequence implements TemplateSequenceModel { private final TemplateSequenceModel seq; ReverseSequence(TemplateSequenceModel seq) { this.seq = seq; } public int size() throws TemplateModelException { return seq.size(); } public TemplateModel get(int index) throws TemplateModelException { return seq.get(seq.size() - 1 - index); } } } static class sortBI extends SequenceBuiltIn { static final int KEY_TYPE_NOT_YET_DETECTED = 0; static final int KEY_TYPE_STRING = 1; static final int KEY_TYPE_NUMBER = 2; static final int KEY_TYPE_DATE = 3; static final int KEY_TYPE_BOOLEAN = 4; TemplateModel calculateResult(TemplateSequenceModel seq) throws TemplateModelException { return sort(seq, null); } static String startErrorMessage(int keyNamesLn) { return (keyNamesLn == 0 ? "?sort" : "?sort_by(...)") + " failed: "; } static String startErrorMessage(int keyNamesLn, int index) { return (keyNamesLn == 0 ? "?sort" : "?sort_by(...)") + " failed at sequence index " + index + (index == 0 ? ": " : " (0-based): "); } static TemplateModelException newInconsistentSortKeyTypeException( int keyNamesLn, String firstType, String firstTypePlural, int index) { String valueInMsg; String valuesInMsg; if (keyNamesLn == 0) { valueInMsg = "value"; valuesInMsg = "values"; } else { valueInMsg = "key value"; valuesInMsg = "key values"; } return new TemplateModelException( startErrorMessage(keyNamesLn, index) + "All " + valuesInMsg + " in the sequence must be " + firstTypePlural + ", because the first " + valueInMsg + " was that. However, the " + valueInMsg + " of the current item isn't a " + firstType + "."); } /** * Sorts a sequence for the sort and sort_by * built-ins. * * @param seq the sequence to sort. * @param keyNames the name of the subvariable whose value is used for the * sorting. If the sorting is done by a sub-subvaruable, then this * will be of length 2, and so on. If the sorting is done by the * sequene items directly, then this argument has to be 0 length * array or null. * @return a new sorted sequence, or the original sequence if the * sequence length was 0. */ static TemplateSequenceModel sort(TemplateSequenceModel seq, String[] keyNames) throws TemplateModelException { int ln = seq.size(); if (ln == 0) return seq; ArrayList res = new ArrayList(ln); int keyNamesLn = keyNames == null ? 0 : keyNames.length; // Copy the Seq into a Java List[KVP] (also detects key type at the 1st item): int keyType = KEY_TYPE_NOT_YET_DETECTED; Comparator keyComparator = null; for (int i = 0; i < ln; i++) { TemplateModel item = seq.get(i); Object key = item; for (int keyNameI = 0; keyNameI < keyNamesLn; keyNameI++) { try { key = ((TemplateHashModel) key).get(keyNames[keyNameI]); } catch (ClassCastException e) { if (!(key instanceof TemplateHashModel)) { throw new TemplateModelException( startErrorMessage(keyNamesLn, i) + (keyNameI == 0 ? "Sequence items must be hashes when using ?sort_by. " : "The " + StringUtil.jQuote(keyNames[keyNameI - 1]) + " subvariable is not a hash, so ?sort_by " + "can't proceed with getting the " + StringUtil.jQuote(keyNames[keyNameI]) + " subvariable.")); } else { throw e; } } if (key == null) { throw new TemplateModelException( startErrorMessage(keyNamesLn, i) + "The " + StringUtil.jQuote(keyNames[keyNameI]) + " subvariable was not found."); } } // for each key if (keyType == KEY_TYPE_NOT_YET_DETECTED) { if (key instanceof TemplateScalarModel) { keyType = KEY_TYPE_STRING; keyComparator = new LexicalKVPComparator( Environment.getCurrentEnvironment().getCollator()); } else if (key instanceof TemplateNumberModel) { keyType = KEY_TYPE_NUMBER; keyComparator = new NumericalKVPComparator( Environment.getCurrentEnvironment() .getArithmeticEngine()); } else if (key instanceof TemplateDateModel) { keyType = KEY_TYPE_DATE; keyComparator = new DateKVPComparator(); } else if (key instanceof TemplateBooleanModel) { keyType = KEY_TYPE_BOOLEAN; keyComparator = new BooleanKVPComparator(); } else { throw new TemplateModelException( startErrorMessage(keyNamesLn, i) + "Values used for sorting must be numbers, strings, " + "date/times or booleans."); } } switch(keyType) { case KEY_TYPE_STRING: try { res.add(new KVP( ((TemplateScalarModel) key).getAsString(), item)); } catch (ClassCastException e) { if (!(key instanceof TemplateScalarModel)) { throw newInconsistentSortKeyTypeException( keyNamesLn, "string", "strings", i); } else { throw e; } } break; case KEY_TYPE_NUMBER: try { res.add(new KVP( ((TemplateNumberModel) key).getAsNumber(), item)); } catch (ClassCastException e) { if (!(key instanceof TemplateNumberModel)) { throw newInconsistentSortKeyTypeException( keyNamesLn, "number", "numbers", i); } } break; case KEY_TYPE_DATE: try { res.add(new KVP( ((TemplateDateModel) key).getAsDate(), item)); } catch (ClassCastException e) { if (!(key instanceof TemplateDateModel)) { throw newInconsistentSortKeyTypeException( keyNamesLn, "date/time", "date/times", i); } } break; case KEY_TYPE_BOOLEAN: try { res.add(new KVP( ((TemplateBooleanModel) key).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE, item)); } catch (ClassCastException e) { if (!(key instanceof TemplateBooleanModel)) { throw newInconsistentSortKeyTypeException( keyNamesLn, "boolean", "booleans", i); } } break; default: throw new RuntimeException("FreeMarker bug: Unexpected key type"); } } // Sort tje List[KVP]: try { Collections.sort(res, keyComparator); } catch (Exception exc) { throw new TemplateModelException( startErrorMessage(keyNamesLn) + "Unexpected error while sorting:" + exc, exc); } // Convert the List[KVP] to List[V]: for (int i = 0; i < ln; i++) { res.set(i, ((KVP) res.get(i)).value); } return new TemplateModelListSequence(res); } /** * Stores a key-value pair. */ private static class KVP { private KVP(Object key, Object value) { this.key = key; this.value = value; } private Object key; private Object value; } private static class NumericalKVPComparator implements Comparator { private ArithmeticEngine ae; private NumericalKVPComparator(ArithmeticEngine ae) { this.ae = ae; } public int compare(Object arg0, Object arg1) { try { return ae.compareNumbers( (Number) ((KVP) arg0).key, (Number) ((KVP) arg1).key); } catch (TemplateException e) { throw new ClassCastException( "Failed to compare numbers: " + e); } } } private static class LexicalKVPComparator implements Comparator { private Collator collator; LexicalKVPComparator(Collator collator) { this.collator = collator; } public int compare(Object arg0, Object arg1) { return collator.compare( ((KVP) arg0).key, ((KVP) arg1).key); } } private static class DateKVPComparator implements Comparator, Serializable { public int compare(Object arg0, Object arg1) { return ((Date) ((KVP) arg0).key).compareTo( (Date) ((KVP) arg1).key); } } private static class BooleanKVPComparator implements Comparator, Serializable { public int compare(Object arg0, Object arg1) { // JDK 1.2 doesn't have Boolean.compareTo boolean b0 = ((Boolean) ((KVP) arg0).key).booleanValue(); boolean b1 = ((Boolean) ((KVP) arg1).key).booleanValue(); if (b0) { return b1 ? 0 : 1; } else { return b1 ? -1 : 0; } } } } static class sort_byBI extends sortBI { TemplateModel calculateResult(TemplateSequenceModel seq) { return new BIMethod(seq); } static class BIMethod implements TemplateMethodModelEx { TemplateSequenceModel seq; BIMethod(TemplateSequenceModel seq) { this.seq = seq; } public Object exec(List params) throws TemplateModelException { if (params.size() == 0) { throw new TemplateModelException( "?sort_by(key) needs exactly 1 argument."); } String[] subvars; Object obj = params.get(0); if (obj instanceof TemplateScalarModel) { subvars = new String[]{((TemplateScalarModel) obj).getAsString()}; } else if (obj instanceof TemplateSequenceModel) { TemplateSequenceModel seq = (TemplateSequenceModel) obj; int ln = seq.size(); subvars = new String[ln]; for (int i = 0; i < ln; i++) { Object item = seq.get(i); try { subvars[i] = ((TemplateScalarModel) item) .getAsString(); } catch (ClassCastException e) { if (!(item instanceof TemplateScalarModel)) { throw new TemplateModelException( "The argument to ?sort_by(key), when it " + "is a sequence, must be a sequence of " + "strings, but the item at index " + i + " is not a string." ); } } } } else { throw new TemplateModelException( "The argument to ?sort_by(key) must be a string " + "(the name of the subvariable), or a sequence of " + "strings (the \"path\" to the subvariable)."); } return sort(seq, subvars); } } } private static boolean isBuggySeqButGoodCollection( TemplateModel model) { return model instanceof CollectionModel ? !((CollectionModel) model).getSupportsIndexedAccess() : false; } static class seq_containsBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); // In 2.3.x only, we prefer TemplateSequenceModel for // backward compatibility. In 2.4.x, we prefer TemplateCollectionModel. if (model instanceof TemplateSequenceModel && !isBuggySeqButGoodCollection(model)) { return new BIMethodForSequence((TemplateSequenceModel) model, env); } else if (model instanceof TemplateCollectionModel) { return new BIMethodForCollection((TemplateCollectionModel) model, env); } else { throw invalidTypeException(model, target, env, "sequence or collection"); } } private static class BIMethodForSequence implements TemplateMethodModelEx { private TemplateSequenceModel m_seq; private Environment m_env; private BIMethodForSequence(TemplateSequenceModel seq, Environment env) { m_seq = seq; m_env = env; } public Object exec(List args) throws TemplateModelException { if (args.size() != 1) throw new TemplateModelException("?seq_contains(...) expects one argument."); TemplateModel arg = (TemplateModel) args.get(0); int size = m_seq.size(); for (int i = 0; i < size; i++) { if (modelsEqual(m_seq.get(i), arg, m_env)) return TemplateBooleanModel.TRUE; } return TemplateBooleanModel.FALSE; } } private static class BIMethodForCollection implements TemplateMethodModelEx { private TemplateCollectionModel m_coll; private Environment m_env; private BIMethodForCollection(TemplateCollectionModel coll, Environment env) { m_coll = coll; m_env = env; } public Object exec(List args) throws TemplateModelException { if (args.size() != 1) throw new TemplateModelException("?seq_contains(...) expects one argument."); TemplateModel arg = (TemplateModel) args.get(0); TemplateModelIterator it = m_coll.iterator(); while (it.hasNext()) { if (modelsEqual(it.next(), arg, m_env)) return TemplateBooleanModel.TRUE; } return TemplateBooleanModel.FALSE; } } } static class seq_index_ofBI extends BuiltIn { private int m_dir; public seq_index_ofBI(int dir) { m_dir = dir; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return new BIMethod(env); } private class BIMethod implements TemplateMethodModelEx { protected final TemplateSequenceModel m_seq; protected final TemplateCollectionModel m_col; protected final Environment m_env; private BIMethod(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); m_seq = model instanceof TemplateSequenceModel && !isBuggySeqButGoodCollection(model) ? (TemplateSequenceModel) model : null; // In 2.3.x only, we deny the possibility of collection // access if there's sequence access. This is so to minimize // the change of compatibility issues; without this, objects // that implement both the sequence and collection interfaces // would suddenly start using the collection interface, and if // that's buggy that would surface now, breaking the application // that despite its bugs has worked earlier. m_col = m_seq == null && model instanceof TemplateCollectionModel ? (TemplateCollectionModel) model : null; if (m_seq == null && m_col == null) { throw invalidTypeException( model, target, env, "sequence or collection"); } m_env = env; } public final Object exec(List args) throws TemplateModelException { int argcnt = args.size(); if (argcnt != 1 && argcnt != 2) { throw new TemplateModelException( getBuiltinTemplate() + " expects 1 or 2 arguments."); } TemplateModel target = (TemplateModel) args.get(0); int foundAtIdx; if (argcnt > 1) { Object obj = args.get(1); if (!(obj instanceof TemplateNumberModel)) { throw new TemplateModelException( getBuiltinTemplate() + "expects a number as its second argument."); } int startIndex = ((TemplateNumberModel) obj).getAsNumber().intValue(); // In 2.3.x only, we prefer TemplateSequenceModel for // backward compatibility: foundAtIdx = m_seq != null ? findInSeq(target, startIndex) : findInCol(target, startIndex); } else { // In 2.3.x only, we prefer TemplateSequenceModel for // backward compatibility: foundAtIdx = m_seq != null ? findInSeq(target) : findInCol(target); } return foundAtIdx == -1 ? Constants.MINUS_ONE : new SimpleNumber(foundAtIdx); } private final String getBuiltinTemplate() { return m_dir == 1 ? "?seq_index_of(...)" : "?seq_last_index_of(...)"; } public int findInSeq(TemplateModel target) throws TemplateModelException { final int seqSize = m_seq.size(); final int actualStartIndex; if (m_dir == 1) { actualStartIndex = 0; } else { actualStartIndex = seqSize - 1; } return findInSeq(target, actualStartIndex, seqSize); } private int findInSeq(TemplateModel target, int startIndex) throws TemplateModelException { int seqSize = m_seq.size(); if (m_dir == 1) { if (startIndex >= seqSize) { return -1; } if (startIndex < 0) { startIndex = 0; } } else { if (startIndex >= seqSize) { startIndex = seqSize - 1; } if (startIndex < 0) { return -1; } } return findInSeq(target, startIndex, seqSize); } private int findInSeq( TemplateModel target, int scanStartIndex, int seqSize) throws TemplateModelException { if (m_dir == 1) { for (int i = scanStartIndex; i < seqSize; i++) { if (modelsEqual(m_seq.get(i), target, m_env)) return i; } } else { for (int i = scanStartIndex; i >= 0; i--) { if (modelsEqual(m_seq.get(i), target, m_env)) return i; } } return -1; } public int findInCol(TemplateModel target) throws TemplateModelException { return findInCol(target, 0, Integer.MAX_VALUE); } protected int findInCol(TemplateModel target, int startIndex) throws TemplateModelException { if (m_dir == 1) { return findInCol(target, startIndex, Integer.MAX_VALUE); } else { return findInCol(target, 0, startIndex); } } protected int findInCol(TemplateModel target, final int allowedRangeStart, final int allowedRangeEnd) throws TemplateModelException { if (allowedRangeEnd < 0) return -1; TemplateModelIterator it = m_col.iterator(); int foundAtIdx = -1; // -1 is the return value for "not found" int idx = 0; searchItem: while (it.hasNext()) { if (idx > allowedRangeEnd) break searchItem; TemplateModel current = it.next(); if (idx >= allowedRangeStart) { if (modelsEqual(current, target, m_env)) { foundAtIdx = idx; if (m_dir == 1) break searchItem; // "find first" // Otherwise it's "find last". } } idx++; } return foundAtIdx; } } } static class chunkBI extends SequenceBuiltIn { TemplateModel calculateResult(TemplateSequenceModel tsm) throws TemplateModelException { return new BIMethod(tsm); } private static class BIMethod implements TemplateMethodModelEx { private final TemplateSequenceModel tsm; private BIMethod(TemplateSequenceModel tsm) { this.tsm = tsm; } public Object exec(List args) throws TemplateModelException { int numArgs = args.size(); if (numArgs != 1 && numArgs !=2) { throw new TemplateModelException( "?chunk(...) expects 1 or 2 arguments."); } Object chunkSize = args.get(0); if (!(chunkSize instanceof TemplateNumberModel)) { throw new TemplateModelException( "?chunk(...) expects a number as " + "its 1st argument."); } return new ChunkedSequence( tsm, ((TemplateNumberModel) chunkSize).getAsNumber().intValue(), numArgs > 1 ? (TemplateModel) args.get(1) : null); } } private static class ChunkedSequence implements TemplateSequenceModel { private final TemplateSequenceModel wrappedTsm; private final int chunkSize; private final TemplateModel fillerItem; private final int numberOfChunks; private ChunkedSequence( TemplateSequenceModel wrappedTsm, int chunkSize, TemplateModel fillerItem) throws TemplateModelException { if (chunkSize < 1) { throw new TemplateModelException( "The 1st argument to ?chunk(...) must be at least 1."); } this.wrappedTsm = wrappedTsm; this.chunkSize = chunkSize; this.fillerItem = fillerItem; numberOfChunks = (wrappedTsm.size() + chunkSize - 1) / chunkSize; } public TemplateModel get(final int chunkIndex) throws TemplateModelException { if (chunkIndex >= numberOfChunks) { return null; } return new TemplateSequenceModel() { private final int baseIndex = chunkIndex * chunkSize; public TemplateModel get(int relIndex) throws TemplateModelException { int absIndex = baseIndex + relIndex; if (absIndex < wrappedTsm.size()) { return wrappedTsm.get(absIndex); } else { return absIndex < numberOfChunks * chunkSize ? fillerItem : null; } } public int size() throws TemplateModelException { return fillerItem != null || chunkIndex + 1 < numberOfChunks ? chunkSize : wrappedTsm.size() - baseIndex; } }; } public int size() throws TemplateModelException { return numberOfChunks; } } } /* * WARNING! This algorithm is duplication of ComparisonExpression.isTrue(...). * Thus, if you update this method, then you have to update that too! */ public static boolean modelsEqual(TemplateModel model1, TemplateModel model2, Environment env) throws TemplateModelException { if (env.isClassicCompatible()) { if (model1 == null) { model1 = TemplateScalarModel.EMPTY_STRING; } if (model2 == null) { model2 = TemplateScalarModel.EMPTY_STRING; } } int comp = -1; if(model1 instanceof TemplateNumberModel && model2 instanceof TemplateNumberModel) { Number first = ((TemplateNumberModel) model1).getAsNumber(); Number second = ((TemplateNumberModel) model2).getAsNumber(); ArithmeticEngine ae = env.getArithmeticEngine(); try { comp = ae.compareNumbers(first, second); } catch (TemplateException ex) { throw new TemplateModelException(ex); } } else if(model1 instanceof TemplateDateModel && model2 instanceof TemplateDateModel) { TemplateDateModel ltdm = (TemplateDateModel)model1; TemplateDateModel rtdm = (TemplateDateModel)model2; int ltype = ltdm.getDateType(); int rtype = rtdm.getDateType(); if(ltype != rtype) { throw new TemplateModelException( "Can not compare dates of different type. Left date is of " + TemplateDateModel.TYPE_NAMES.get(ltype) + " type, right date is of " + TemplateDateModel.TYPE_NAMES.get(rtype) + " type."); } if(ltype == TemplateDateModel.UNKNOWN) { throw new TemplateModelException( "Left date is of UNKNOWN type, and can not be compared."); } if(rtype == TemplateDateModel.UNKNOWN) { throw new TemplateModelException( "Right date is of UNKNOWN type, and can not be compared."); } Date first = ltdm.getAsDate(); Date second = rtdm.getAsDate(); comp = first.compareTo(second); } else if(model1 instanceof TemplateScalarModel && model2 instanceof TemplateScalarModel) { String first = ((TemplateScalarModel) model1).getAsString(); String second = ((TemplateScalarModel) model2).getAsString(); comp = env.getCollator().compare(first, second); } else if(model1 instanceof TemplateBooleanModel && model2 instanceof TemplateBooleanModel) { boolean first = ((TemplateBooleanModel)model1).getAsBoolean(); boolean second = ((TemplateBooleanModel)model2).getAsBoolean(); comp = (first ? 1 : 0) - (second ? 1 : 0); } return (comp == 0); } }libfreemarker-java-2.3.19.orig/src/freemarker/core/PropertySetting.java0000644000175000017500000001214311723544471025526 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.Template; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; /** * An instruction that sets a property of the template rendering * environment. */ final class PropertySetting extends TemplateElement { private final String key; private final Expression value; PropertySetting(String key, Expression value) { this.key = key; this.value = value; } void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine) throws ParseException { super.setLocation(template, beginColumn, beginLine, endColumn, endLine); if (!key.equals(Configurable.LOCALE_KEY) && !key.equals(Configurable.NUMBER_FORMAT_KEY) && !key.equals(Configurable.TIME_FORMAT_KEY) && !key.equals(Configurable.DATE_FORMAT_KEY) && !key.equals(Configurable.DATETIME_FORMAT_KEY) && !key.equals(Configurable.TIME_ZONE_KEY) && !key.equals(Configurable.BOOLEAN_FORMAT_KEY) && !key.equals(Configurable.CLASSIC_COMPATIBLE_KEY) && !key.equals(Configurable.URL_ESCAPING_CHARSET_KEY)) { throw new ParseException( "Error " + getStartLocation() + "\nInvalid setting name, or it is not allowed to change " + "the value of the setting with FTL: " + key, beginLine, beginColumn); } } void accept(Environment env) throws TemplateException { TemplateModel mval = value.getAsTemplateModel(env); String strval; if (mval instanceof TemplateScalarModel) { strval = ((TemplateScalarModel) mval).getAsString(); } else if (mval instanceof TemplateBooleanModel) { strval = ((TemplateBooleanModel) mval).getAsBoolean() ? "true" : "false"; } else if (mval instanceof TemplateNumberModel) { strval = ((TemplateNumberModel) mval).getAsNumber().toString(); } else { strval = value.getStringValue(env); } env.setSetting(key, strval); } public String getCanonicalForm() { return "<#setting " + key + "=" + value.getCanonicalForm() + "/>"; } public String getDescription() { return "setting " + key + " set to " + "\"" + value + "\" " + "[" + getStartLocation() + "]"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/IteratorBlock.java0000644000175000017500000002032511723544467025116 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import freemarker.template.SimpleNumber; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateSequenceModel; /** * An instruction that processes a list or foreach block */ final class IteratorBlock extends TemplateElement { private Expression listExpression; private String indexName; private boolean isForEach; /** * @param listExpression a variable referring to a sequence or collection * @param indexName an arbitrary index variable name * @param nestedBlock the nestedBlock to iterate over */ IteratorBlock(Expression listExpression, String indexName, TemplateElement nestedBlock, boolean isForEach) { this.listExpression = listExpression; this.indexName = indexName; this.isForEach = isForEach; this.nestedBlock = nestedBlock; } void accept(Environment env) throws TemplateException, IOException { TemplateModel baseModel = listExpression.getAsTemplateModel(env); if (baseModel == null) { if (env.isClassicCompatible()) { // Classic behavior of simply ignoring null references. return; } assertNonNull(baseModel, listExpression, env); } env.visit(new Context(baseModel)); } public String getCanonicalForm() { if (isForEach) { StringBuffer buf = new StringBuffer("<#foreach "); buf.append(indexName); buf.append(" in "); buf.append(listExpression.getCanonicalForm()); buf.append(">"); if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } buf.append(""); return buf.toString(); } else { StringBuffer buf = new StringBuffer("<#list "); buf.append(listExpression.getCanonicalForm()); buf.append(" as "); buf.append(indexName); buf.append(">"); if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } buf.append(""); return buf.toString(); } } public String getDescription() { if (isForEach) { return "foreach " + indexName + " in " + listExpression; } else { return "list " + listExpression + " as " + indexName; } } /** * A helper class that holds the context of the loop. */ class Context implements LocalContext { private boolean hasNext; private TemplateModel loopVar; private int index; private Collection variableNames = null; private TemplateModel list; Context(TemplateModel list) { this.list = list; } void runLoop(Environment env) throws TemplateException, IOException { if (list instanceof TemplateCollectionModel) { TemplateCollectionModel baseListModel = (TemplateCollectionModel)list; TemplateModelIterator it = baseListModel.iterator(); hasNext = it.hasNext(); while (hasNext) { loopVar = it.next(); hasNext = it.hasNext(); if (nestedBlock != null) { env.visit(nestedBlock); } index++; } } else if (list instanceof TemplateSequenceModel) { TemplateSequenceModel tsm = (TemplateSequenceModel) list; int size = tsm.size(); for (index =0; index index +1); if (nestedBlock != null) { env.visit(nestedBlock); } } } else if (env.isClassicCompatible()) { loopVar = list; if (nestedBlock != null) { env.visit(nestedBlock); } } else { throw invalidTypeException(list, listExpression, env, "collection or sequence"); } } public TemplateModel getLocalVariable(String name) { if (name.startsWith(indexName)) { switch(name.length() - indexName.length()) { case 0: return loopVar; case 6: if(name.endsWith("_index")) { return new SimpleNumber(index); } break; case 9: if(name.endsWith("_has_next")) { return hasNext ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } break; } } return null; } public Collection getLocalVariableNames() { if(variableNames == null) { variableNames = new ArrayList(3); variableNames.add(indexName); variableNames.add(indexName + "_index"); variableNames.add(indexName + "_has_next"); } return variableNames; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/AddConcatExpression.java0000644000175000017500000002326011723544467026253 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import java.util.*; /** * An operator for the + operator. Note that this is treated * separately from the other 4 arithmetic operators, * since + is overloaded to mean string concatenation. * @author Jonathan Revusky */ final class AddConcatExpression extends Expression { private final Expression left; private final Expression right; AddConcatExpression(Expression left, Expression right) { this.left = left; this.right = right; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel leftModel = left.getAsTemplateModel(env); TemplateModel rightModel = right.getAsTemplateModel(env); if (leftModel instanceof TemplateNumberModel && rightModel instanceof TemplateNumberModel) { Number first = EvaluationUtil.getNumber((TemplateNumberModel) leftModel, left, env); Number second = EvaluationUtil.getNumber((TemplateNumberModel) rightModel, right, env); ArithmeticEngine ae = env != null ? env.getArithmeticEngine() : getTemplate().getArithmeticEngine(); return new SimpleNumber(ae.add(first, second)); } else if(leftModel instanceof TemplateSequenceModel && rightModel instanceof TemplateSequenceModel) { return new ConcatenatedSequence((TemplateSequenceModel)leftModel, (TemplateSequenceModel)rightModel); } else { try { String s1 = getStringValue(leftModel, left, env); if(s1 == null) s1 = "null"; String s2 = getStringValue(rightModel, right, env); if(s2 == null) s2 = "null"; return new SimpleScalar(s1.concat(s2)); } catch (NonStringException e) { if (leftModel instanceof TemplateHashModel && rightModel instanceof TemplateHashModel) { if (leftModel instanceof TemplateHashModelEx && rightModel instanceof TemplateHashModelEx) { TemplateHashModelEx leftModelEx = (TemplateHashModelEx)leftModel; TemplateHashModelEx rightModelEx = (TemplateHashModelEx)rightModel; if (leftModelEx.size() == 0) { return rightModelEx; } else if (rightModelEx.size() == 0) { return leftModelEx; } else { return new ConcatenatedHashEx(leftModelEx, rightModelEx); } } else { return new ConcatenatedHash((TemplateHashModel)leftModel, (TemplateHashModel)rightModel); } } else { throw e; } } } } boolean isLiteral() { return constantValue != null || (left.isLiteral() && right.isLiteral()); } Expression _deepClone(String name, Expression subst) { return new AddConcatExpression(left.deepClone(name, subst), right.deepClone(name, subst)); } public String getCanonicalForm() { return left.getCanonicalForm() + " + " + right.getCanonicalForm(); } private static final class ConcatenatedSequence implements TemplateSequenceModel { private final TemplateSequenceModel left; private final TemplateSequenceModel right; ConcatenatedSequence(TemplateSequenceModel left, TemplateSequenceModel right) { this.left = left; this.right = right; } public int size() throws TemplateModelException { return left.size() + right.size(); } public TemplateModel get(int i) throws TemplateModelException { int ls = left.size(); return i < ls ? left.get(i) : right.get(i - ls); } } private static class ConcatenatedHash implements TemplateHashModel { protected final TemplateHashModel left; protected final TemplateHashModel right; ConcatenatedHash(TemplateHashModel left, TemplateHashModel right) { this.left = left; this.right = right; } public TemplateModel get(String key) throws TemplateModelException { TemplateModel model = right.get(key); return (model != null) ? model : left.get(key); } public boolean isEmpty() throws TemplateModelException { return left.isEmpty() && right.isEmpty(); } } private static final class ConcatenatedHashEx extends ConcatenatedHash implements TemplateHashModelEx { private CollectionAndSequence keys; private CollectionAndSequence values; private int size; ConcatenatedHashEx(TemplateHashModelEx left, TemplateHashModelEx right) { super(left, right); } public int size() throws TemplateModelException { initKeys(); return size; } public TemplateCollectionModel keys() throws TemplateModelException { initKeys(); return keys; } public TemplateCollectionModel values() throws TemplateModelException { initValues(); return values; } private void initKeys() throws TemplateModelException { if (keys == null) { HashSet keySet = new HashSet(); SimpleSequence keySeq = new SimpleSequence(32); addKeys(keySet, keySeq, (TemplateHashModelEx)this.left); addKeys(keySet, keySeq, (TemplateHashModelEx)this.right); size = keySet.size(); keys = new CollectionAndSequence(keySeq); } } private static void addKeys(Set set, SimpleSequence keySeq, TemplateHashModelEx hash) throws TemplateModelException { TemplateModelIterator it = hash.keys().iterator(); while (it.hasNext()) { TemplateScalarModel tsm = (TemplateScalarModel)it.next(); if (set.add(tsm.getAsString())) { // The first occurence of the key decides the index; // this is consisten with stuff like java.util.LinkedHashSet. keySeq.add(tsm); } } } private void initValues() throws TemplateModelException { if (values == null) { SimpleSequence seq = new SimpleSequence(size()); // Note: size() invokes initKeys() if needed. int ln = keys.size(); for (int i = 0; i < ln; i++) { seq.add(get(((TemplateScalarModel)keys.get(i)).getAsString())); } values = new CollectionAndSequence(seq); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Case.java0000644000175000017500000000752611723544470023227 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.*; /** * Represents a case in a switch statement. */ final class Case extends TemplateElement { // might as well just make these package-visible // so the Switch can use them, no need to be too anal-retentive boolean isDefault; Expression expression; Case(Expression expression, TemplateElement nestedBlock, boolean isDefault) { this.expression = expression; this.nestedBlock = nestedBlock; this.isDefault = isDefault; } void accept(Environment env) throws TemplateException, IOException { if (nestedBlock != null) { env.visit(nestedBlock); } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer(); if (isDefault) { buf.append("<#default>"); } else { buf.append("<#case "); buf.append(expression.getCanonicalForm()); buf.append(">"); } if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } return buf.toString(); } public String getDescription() { if (isDefault) { return "default case"; } return "case " + expression; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/DynamicKeyName.java0000644000175000017500000002425311723544471025207 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.ArrayList; import freemarker.template.*; /** * A unary operator that uses the string value of an expression as a hash key. * It associates with the Identifier or Dot to its left. */ final class DynamicKeyName extends Expression { private final Expression nameExpression; private final Expression target; DynamicKeyName(Expression target, Expression nameExpression) { this.target = target; this.nameExpression = nameExpression; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel targetModel = target.getAsTemplateModel(env); assertNonNull(targetModel, target, env); if (nameExpression instanceof Range) { return dealWithRangeKey(targetModel, (Range) nameExpression, env); } TemplateModel keyModel = nameExpression.getAsTemplateModel(env); if(keyModel == null) { if(env.isClassicCompatible()) { keyModel = TemplateScalarModel.EMPTY_STRING; } else { assertNonNull(keyModel, nameExpression, env); } } if (keyModel instanceof TemplateNumberModel) { int index = EvaluationUtil.getNumber(keyModel, nameExpression, env).intValue(); return dealWithNumericalKey(targetModel, index, env); } if (keyModel instanceof TemplateScalarModel) { String key = EvaluationUtil.getString((TemplateScalarModel)keyModel, nameExpression, env); return dealWithStringKey(targetModel, key, env); } throw invalidTypeException(keyModel, nameExpression, env, "number, range, or string"); } private TemplateModel dealWithNumericalKey(TemplateModel targetModel, int index, Environment env) throws TemplateException { if (targetModel instanceof TemplateSequenceModel) { TemplateSequenceModel tsm = (TemplateSequenceModel) targetModel; int size = Integer.MAX_VALUE; try { size = tsm.size(); } catch (Exception e) {} return index= sequence.size()) { String msg = range.left.getStartLocation() + "\nLeft side index of range out of bounds, is " + start + ", but the sequence has only " + sequence.size() + " element(s) " + "(note that indices are 0 based, and ranges are inclusive)."; throw new TemplateException(msg, env); } if (end >= sequence.size()) { String msg = range.right.getStartLocation() + "\nRight side index of range out of bounds, is " + end + ", but the sequence has only " + sequence.size() + " element(s)." + "(note that indices are 0 based, and ranges are inclusive)."; throw new TemplateException(msg, env); } ArrayList list = new ArrayList(1+Math.abs(start-end)); if (start>end) { for (int i = start; i>=end; i--) { list.add(sequence.get(i)); } } else { for (int i = start; i<=end; i++) { list.add(sequence.get(i)); } } return new SimpleSequence(list); } try { String s = target.getStringValue(env); if (!hasRhs) end = s.length() -1; if (start < 0) { String msg = range.left.getStartLocation() + "\nNegative starting index for range " + range + " : " + start; throw new TemplateException(msg, env); } if (end < 0) { String msg = range.left.getStartLocation() + "\nNegative ending index for range " + range + " : " + end; throw new TemplateException(msg, env); } if (start > s.length()) { String msg = range.left.getStartLocation() + "\nLeft side of range out of bounds, is: " + start + "\nbut string " + targetModel + " has " + s.length() + " elements."; throw new TemplateException(msg, env); } if (end > s.length()) { String msg = range.right.getStartLocation() + "\nRight side of range out of bounds, is: " + end + "\nbut string " + targetModel + " is only " + s.length() + " characters."; throw new TemplateException(msg, env); } try { return new SimpleScalar(s.substring(start, end+1)); } catch (RuntimeException re) { String msg = "Error " + getStartLocation(); throw new TemplateException(msg, re, env); } } catch(NonStringException e) { throw invalidTypeException(target.getAsTemplateModel(env), target, env, "number, scalar, or sequence"); } } public String getCanonicalForm() { return target.getCanonicalForm() + "[" + nameExpression.getCanonicalForm() + "]"; } boolean isLiteral() { return constantValue != null || (target.isLiteral() && nameExpression.isLiteral()); } Expression _deepClone(String name, Expression subst) { return new DynamicKeyName(target.deepClone(name, subst), nameExpression.deepClone(name, subst)); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ParentheticalExpression.java0000644000175000017500000000650711723544470027215 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; final class ParentheticalExpression extends Expression { private final Expression nested; ParentheticalExpression(Expression nested) { this.nested = nested; } boolean isTrue(Environment env) throws TemplateException { return nested.isTrue(env); } public String getCanonicalForm() { return "(" + nested.getCanonicalForm() + ")"; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return nested.getAsTemplateModel(env); } public boolean isLiteral() { return nested.isLiteral(); } Expression _deepClone(String name, Expression subst) { return new ParentheticalExpression(nested.deepClone(name, subst)); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FlushInstruction.java0000644000175000017500000000602011723544471025664 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; /** * An instruction that flushes the output stream. * @version $Id: FlushInstruction.java,v 1.2 2004/01/06 17:06:42 szegedia Exp $ */ final class FlushInstruction extends TemplateElement { void accept(Environment env) throws IOException { env.getOut().flush(); } public String getCanonicalForm() { return "<#flush/>"; } public String getDescription() { return "flush instruction"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ArithmeticExpression.java0000644000175000017500000001261111723544471026515 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * An operator for arithmetic operations. Note that the + operator * also does string concatenation for backward compatibility. * @author Jonathan Revusky */ final class ArithmeticExpression extends Expression { static final int SUBSTRACTION = 0; static final int MULTIPLICATION = 1; static final int DIVISION = 2; static final int MODULUS = 3; private static final char[] OPERATORS = new char[] {'-','*','/','%'}; private final Expression left; private final Expression right; private final int operation; ArithmeticExpression(Expression left, Expression right, int operation) { this.left = left; this.right = right; this.operation = operation; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel leftModel = left.getAsTemplateModel(env); TemplateModel rightModel = right.getAsTemplateModel(env); boolean leftIsNumber = (leftModel instanceof TemplateNumberModel); boolean rightIsNumber = (rightModel instanceof TemplateNumberModel); boolean bothNumbers = leftIsNumber && rightIsNumber; if (!bothNumbers) { String msg = "Error " + getStartLocation(); if (!leftIsNumber) { msg += "\nExpression " + left + " is not numerical"; } if (!rightIsNumber) { msg += "\nExpression " + right + " is not numerical"; } throw new NonNumericalException(msg, env); } Number first = EvaluationUtil.getNumber(leftModel, left, env); Number second = EvaluationUtil.getNumber(rightModel, right, env); ArithmeticEngine ae = env != null ? env.getArithmeticEngine() : getTemplate().getArithmeticEngine(); switch (operation) { case SUBSTRACTION : return new SimpleNumber(ae.subtract(first, second)); case MULTIPLICATION : return new SimpleNumber(ae.multiply(first, second)); case DIVISION : return new SimpleNumber(ae.divide(first, second)); case MODULUS : return new SimpleNumber(ae.modulus(first, second)); default: throw new TemplateException("unknown operation : " + operation, env); } } public String getCanonicalForm() { return left.getCanonicalForm() + ' ' + OPERATORS[operation] + ' ' + right.getCanonicalForm(); } boolean isLiteral() { return constantValue != null || (left.isLiteral() && right.isLiteral()); } Expression _deepClone(String name, Expression subst) { return new ArithmeticExpression(left.deepClone(name, subst), right.deepClone(name, subst), operation); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/StopInstruction.java0000644000175000017500000000656211723544470025542 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; /** * Represents a <stop> instruction to abort template processing. * @author Jonathan Revusky */ final class StopInstruction extends TemplateElement { private Expression exp; StopInstruction(Expression exp) { this.exp = exp; } void accept(Environment env) throws TemplateException { if (exp == null) { throw new StopException(env); } throw new StopException(env, exp.getStringValue(env)); } public String getCanonicalForm() { String expString = exp == null ? "" : " " + exp.getCanonicalForm(); return "<#stop" + expString + "/>"; } public String getDescription() { return "stop" + " [" + getStartLocation() + "]"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TemplateClassResolver.java0000644000175000017500000001370711723544470026635 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.Execute; import freemarker.template.utility.ObjectConstructor; /** * Used by built-ins and other template language features that get a class * based on a string. This can be handy both for implementing security * restrictions and for working around local class-loader issues. * * The implementation should be thread-safe, unless an * instance is always only used in a single {@link Environment} object. * * @see Configurable#setNewBuiltinClassResolver(TemplateClassResolver) */ public interface TemplateClassResolver { /** * Simply calls {@link ClassUtil#forName(String)}. */ TemplateClassResolver UNRESTRICTED_RESOLVER = new TemplateClassResolver() { public Class resolve(String className, Environment env, Template template) throws TemplateException { try { return ClassUtil.forName(className); } catch (ClassNotFoundException e) { throw new TemplateException(e, env); } } }; /** * Same as {@link #UNRESTRICTED_RESOLVER}, except that it doesn't allow * resolving {@link ObjectConstructor}. */ TemplateClassResolver SAFER_RESOLVER = new TemplateClassResolver() { public Class resolve(String className, Environment env, Template template) throws TemplateException { if (className.equals(ObjectConstructor.class.getName()) || className.equals(Execute.class.getName()) || className.equals("freemarker.template.utility.JythonRuntime")) { throw new TemplateException( "Instantiating " + className + " is not allowed in the " + "template for security reasons.", env); } try { return ClassUtil.forName(className); } catch (ClassNotFoundException e) { throw new TemplateException(e, env); } } }; /** * Doesn't allow resolving any classes. */ TemplateClassResolver ALLOWS_NOTHING_RESOLVER = new TemplateClassResolver() { public Class resolve(String className, Environment env, Template template) throws TemplateException { throw new TemplateException( "Instantiating " + className + " is not allowed in the " + "template for security reasons.", env); } }; /** * Gets a {@link Class} based on the class name. * * @param className the full-qualified class name * @param env the environment in which the template executes * @param template the template where the operation that require the * class resolution resides in. This is null if the * call doesn't come from a template. * * @throws TemplateException if the class can't be found or shouldn't be * accessed from a template for security reasons. */ Class resolve(String className, Environment env, Template template) throws TemplateException; } libfreemarker-java-2.3.19.orig/src/freemarker/core/NonDateException.java0000644000175000017500000000600411723544471025552 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; /** * Indicates that a date, time or date+time was expected. */ public class NonDateException extends TemplateException { public NonDateException(Environment env) { super("expecting date/time value here", env); } public NonDateException(String description, Environment env) { super(description, env); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Identifier.java0000644000175000017500000000723511723544472024435 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * A reference to a top-level variable */ final class Identifier extends Expression { private final String name; Identifier(String name) { this.name = name; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { try { return env.getVariable(name); } catch (NullPointerException e) { if (env == null) { throw new TemplateException("Variables are not available " + "(certainly you are in a parse-time executed directive). The name of the variable " + "you tried to read: " + name, null); } else { throw e; } } } public String toString() { return name; } public String getCanonicalForm() { return name; } boolean isLiteral() { return false; } Expression _deepClone(String name, Expression subst) { if(this.name.equals(name)) { return subst.deepClone(null, null); } return new Identifier(this.name); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/AssignmentInstruction.java0000644000175000017500000001174411723544470026723 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.util.*; import freemarker.template.TemplateException; /** * An instruction that contains one or more assignments */ final class AssignmentInstruction extends TemplateElement { private int scope; private Expression namespaceExp; AssignmentInstruction(int scope) { this.scope = scope; nestedElements = new ArrayList(1); } void addAssignment(Assignment ass) { nestedElements.add(ass); } void setNamespaceExp(Expression namespaceExp) { this.namespaceExp = namespaceExp; for (int i=0; i"); return buf.toString(); } public String getDescription() { String tag = "local "; if (scope == Assignment.GLOBAL) { tag = "global "; } else if (scope == Assignment.NAMESPACE) { tag = "assign "; } tag += "assignment"; if (nestedElements.size() > 1) { tag += "s"; } return tag; } public TemplateElement postParseCleanup(boolean stripWhitespace) throws ParseException { super.postParseCleanup(stripWhitespace); if (nestedElements.size() == 1) { Assignment ass = (Assignment) nestedElements.get(0); ass.setLocation(getTemplate(), this, this); return ass; } return this; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Token.java0000644000175000017500000000532011723544470023422 0ustar ebourgebourg/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ package freemarker.core; /** * Describes the input token stream. */ class Token implements java.io.Serializable { /** * An integer that describes the kind of this token. This numbering * system is determined by JavaCCParser, and a table of these numbers is * stored in the file ...Constants.java. */ public int kind; /** * beginLine and beginColumn describe the position of the first character * of this token; endLine and endColumn describe the position of the * last character of this token. */ public int beginLine, beginColumn, endLine, endColumn; /** * The string image of the token. */ public String image; /** * A reference to the next regular (non-special) token from the input * stream. If this is the last token from the input stream, or if the * token manager has not read tokens beyond this one, this field is * set to null. This is true only if this token is also a regular * token. Otherwise, see below for a description of the contents of * this field. */ public Token next; /** * This field is used to access special tokens that occur prior to this * token, but after the immediately preceding regular (non-special) token. * If there are no such special tokens, this field is set to null. * When there are more than one such special token, this field refers * to the last of these special tokens, which in turn refers to the next * previous special token through its specialToken field, and so on * until the first special token (whose specialToken field is null). * The next fields of special tokens refer to other special tokens that * immediately follow it (without an intervening regular token). If there * is no such token, this field is null. */ public Token specialToken; /** * Returns the image. */ public String toString() { return image; } /** * Returns a new Token object, by default. However, if you want, you * can create and return subclass objects based on the value of ofKind. * Simply add the cases to the switch for all those special cases. * For example, if you have a subclass of Token called IDToken that * you want to create if ofKind is ID, simlpy add something like : * * case MyParserConstants.ID : return new IDToken(); * * to the following switch statement. Then you can cast matchedToken * variable to the appropriate type and use it in your lexical actions. */ public static final Token newToken(int ofKind) { switch(ofKind) { default : return new Token(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BreakInstruction.java0000644000175000017500000000621111723544470025630 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; /** * Represents a <break> instruction to break out of a loop. * @author Jonathan Revusky */ final class BreakInstruction extends TemplateElement { void accept(Environment env) { throw Break.INSTANCE; } public String getCanonicalForm() { return "<#break/>"; } public String getDescription() { return "break" + " [" + getStartLocation() + "]"; } static class Break extends RuntimeException { static final Break INSTANCE = new Break(); private Break() { } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/DateBuiltins.java0000644000175000017500000002276711723544471024750 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.Date; import java.util.List; import java.util.TimeZone; import freemarker.template.AdapterTemplateModel; import freemarker.template.SimpleScalar; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateException; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateScalarModel; import freemarker.template.utility.DateUtil; import freemarker.template.utility.StringUtil; import freemarker.template.utility.UnrecognizedTimeZoneException; /** * A holder for built-ins that operate exclusively on {@link TemplateDateModel}-a. */ abstract class DateBuiltins { abstract static class DateBuiltin extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateDateModel) { TemplateDateModel tdm = (TemplateDateModel) model; return calculateResult(EvaluationUtil.getDate(tdm, target, env), tdm.getDateType(), env); } else { if(model == null) { throw new InvalidReferenceException(target + " is undefined.", env); } throw new NonDateException( target + " should be a date, time, or date+time, but it's a(n) " + model.getClass().getName(), env); } } /** Override this to implement the built-in. */ protected abstract TemplateModel calculateResult( Date date, int dateType, Environment env) throws TemplateException; } static abstract class AbstractISOBI extends DateBuiltin { protected final String biName; protected final boolean showOffset; protected final int accuracy; protected AbstractISOBI(String biName, boolean showOffset, int accuracy) { this.biName = biName; this.showOffset = showOffset; this.accuracy = accuracy; } protected void checkDateTypeNotUnknown(int dateType, Environment env) throws TemplateException { if (dateType == TemplateDateModel.UNKNOWN) { throw new TemplateException( "Unknown date type: ?" + biName + " needs a date value " + "where it's known if it's a date-only, time-only, or " + "date+time value. Use ?time, ?date or ?datetime " + "before ? " + biName + " to estabilish that.", env); } } } /** * Implements {@code ?iso_utc} and {@code ?iso_local} variants, but not * {@code ?iso(timeZone)}. */ static class iso_tz_BI extends AbstractISOBI { private final boolean useUTC; iso_tz_BI(String biName, boolean showOffset, int accuracy, boolean useUTC) { super(biName, showOffset, accuracy); this.useUTC = useUTC; } protected TemplateModel calculateResult( Date date, int dateType, Environment env) throws TemplateException { checkDateTypeNotUnknown(dateType, env); return new SimpleScalar(DateUtil.dateToISO8601String( date, dateType != TemplateDateModel.TIME, dateType != TemplateDateModel.DATE, showOffset && dateType != TemplateDateModel.DATE, accuracy, useUTC ? DateUtil.UTC : env.getTimeZone(), env.getISOBuiltInCalendar())); } } /** * Implements {@code ?iso(timeZone)}. */ static class iso_BI extends AbstractISOBI { iso_BI(String biName, boolean showOffset, int accuracy) { super(biName, showOffset, accuracy); } protected TemplateModel calculateResult( Date date, int dateType, Environment env) throws TemplateException { checkDateTypeNotUnknown(dateType, env); return new Result(date, dateType, env); } class Result implements TemplateMethodModelEx { private final Date date; private final int dateType; private final Environment env; Result(Date date, int dateType, Environment env) { this.date = date; this.dateType = dateType; this.env = env; } public Object exec(List args) throws TemplateModelException { if (args.size() != 1) { throw new TemplateModelException( "?" + biName + "(...) expects exactly 1 argument, but had " + args.size() + "."); } TemplateModel tzArgTM = (TemplateModel) args.get(0); TimeZone tzArg; Object adaptedObj; if (tzArgTM instanceof AdapterTemplateModel && (adaptedObj = ((AdapterTemplateModel) tzArgTM) .getAdaptedObject(TimeZone.class)) instanceof TimeZone) { tzArg = (TimeZone) adaptedObj; } else if (tzArgTM instanceof TemplateScalarModel) { String tzName = ((TemplateScalarModel) tzArgTM).getAsString(); try { tzArg = DateUtil.getTimeZone(tzName); } catch (UnrecognizedTimeZoneException e) { throw new TemplateModelException( "The time zone string specified for ?" + biName + "(...) is not recognized as a valid time zone name: " + StringUtil.jQuote(tzName)); } } else { throw new TemplateModelException( "The argument to ?" + biName + "(...) must be a String or a " + "java.util.TimeZone but it was a " + (tzArgTM != null ? tzArgTM.getClass().getName() : "null") + "."); } return new SimpleScalar(DateUtil.dateToISO8601String( date, dateType != TemplateDateModel.TIME, dateType != TemplateDateModel.DATE, showOffset && dateType != TemplateDateModel.DATE, accuracy, tzArg, env.getISOBuiltInCalendar())); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FMParserTokenManager.java0000644000175000017500000074071311723544471026332 0ustar ebourgebourg/* Generated By:JavaCC: Do not edit this line. FMParserTokenManager.java */ package freemarker.core; import freemarker.template.*; import freemarker.template.utility.StringUtil; import freemarker.template.utility.DeepUnwrap; import java.io.*; import java.util.*; class FMParserTokenManager implements FMParserConstants { /** The noparseTag is set when we enter a block of text that the parser more or less ignores. These are and . This variable tells us what the closing tag should be, and when we hit that, we resume parsing. Note that with this scheme, and tags cannot nest recursively, but it is not clear how important that is. */ String noparseTag; /** Keeps track of how deeply nested we have the hash literals. This is necessary since we need to be able to distinguish the } used to close a hash literal and the one used to close a ${ */ private int hashLiteralNesting; private int parenthesisNesting; private int bracketNesting; private boolean inFTLHeader; boolean strictEscapeSyntax, onlyTextOutput, altDirectiveSyntax, autodetectTagSyntax, directiveSyntaxEstablished, inInvocation; int incompatibleChanges; String templateName; // This method checks if we are in a strict mode where all // FreeMarker directives must start with <#. It also handled // tag syntax detection. If you update this logic, take a look // at the UNKNOWN_DIRECTIVE token too. private void strictSyntaxCheck(Token tok, int newLexState) { if (onlyTextOutput) { tok.kind = PRINTABLE_CHARS; return; } char firstChar = tok.image.charAt(0); if (autodetectTagSyntax && !directiveSyntaxEstablished) { altDirectiveSyntax = (firstChar == '['); } if ((firstChar == '[' && !altDirectiveSyntax) || (firstChar == '<' && altDirectiveSyntax)) { tok.kind = PRINTABLE_CHARS; return; } if (!strictEscapeSyntax) { SwitchTo(newLexState); return; } if (!altDirectiveSyntax) { if (!tok.image.startsWith("<#") && !tok.image.startsWith("0) { --bracketNesting; } else { tok.kind=DIRECTIVE_END; if (inFTLHeader) { eatNewline(); inFTLHeader = false; } SwitchTo(DEFAULT); } } private void eatNewline() { int charsRead = 0; try { while (true) { char c = input_stream.readChar(); ++charsRead; if (!Character.isWhitespace(c)) { input_stream.backup(charsRead); return; } else if (c=='\r') { char next = input_stream.readChar(); ++charsRead; if (next != '\n') { input_stream.backup(1); } return; } else if (c=='\n') { return; } } } catch (IOException ioe) { input_stream.backup(charsRead); } } private void ftlHeader(Token matchedToken) { if (!directiveSyntaxEstablished) { altDirectiveSyntax = matchedToken.image.charAt(0) == '['; directiveSyntaxEstablished = true; autodetectTagSyntax = false; } String img = matchedToken.image; char firstChar = img.charAt(0); char lastChar = img.charAt(img.length() -1); if ((firstChar == '[' && !altDirectiveSyntax) || (firstChar == '<' && altDirectiveSyntax)) { matchedToken.kind = PRINTABLE_CHARS; } if (matchedToken.kind != PRINTABLE_CHARS) { if (lastChar != '>' && lastChar != ']') { SwitchTo(FM_EXPRESSION); inFTLHeader = true; } else { eatNewline(); } } } public java.io.PrintStream debugStream = System.out; public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } private final int jjMoveStringLiteralDfa0_7() { return jjMoveNfa_7(0, 0); } private final void jjCheckNAdd(int state) { if (jjrounds[state] != jjround) { jjstateSet[jjnewStateCnt++] = state; jjrounds[state] = jjround; } } private final void jjAddStates(int start, int end) { do { jjstateSet[jjnewStateCnt++] = jjnextStates[start]; } while (start++ != end); } private final void jjCheckNAddTwoStates(int state1, int state2) { jjCheckNAdd(state1); jjCheckNAdd(state2); } private final void jjCheckNAddStates(int start, int end) { do { jjCheckNAdd(jjnextStates[start]); } while (start++ != end); } private final void jjCheckNAddStates(int start) { jjCheckNAdd(jjnextStates[start]); jjCheckNAdd(jjnextStates[start + 1]); } static final long[] jjbitVec0 = { 0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; static final long[] jjbitVec2 = { 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL }; private final int jjMoveNfa_7(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 13; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 0: if ((0xefffdfffffffffffL & l) != 0L) { if (kind > 131) kind = 131; jjCheckNAdd(6); } else if ((0x1000200000000000L & l) != 0L) { if (kind > 132) kind = 132; } if (curChar == 45) jjAddStates(0, 1); else if (curChar == 60) jjstateSet[jjnewStateCnt++] = 1; break; case 1: if (curChar == 47) jjCheckNAddTwoStates(2, 3); break; case 2: if (curChar == 35) jjCheckNAdd(3); break; case 4: if ((0x100002600L & l) != 0L) jjAddStates(2, 3); break; case 5: if (curChar == 62 && kind > 130) kind = 130; break; case 6: if ((0xefffdfffffffffffL & l) == 0L) break; if (kind > 131) kind = 131; jjCheckNAdd(6); break; case 7: if ((0x1000200000000000L & l) != 0L && kind > 132) kind = 132; break; case 8: if (curChar == 45) jjAddStates(0, 1); break; case 9: if (curChar == 62 && kind > 129) kind = 129; break; case 10: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 9; break; case 12: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 11; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 0: if ((0xfffffffff7ffffffL & l) != 0L) { if (kind > 131) kind = 131; jjCheckNAdd(6); } else if (curChar == 91) { if (kind > 132) kind = 132; } if (curChar == 91) jjstateSet[jjnewStateCnt++] = 1; break; case 3: if ((0x7fffffe07fffffeL & l) != 0L) jjAddStates(4, 6); break; case 5: if (curChar == 93 && kind > 130) kind = 130; break; case 6: if ((0xfffffffff7ffffffL & l) == 0L) break; if (kind > 131) kind = 131; jjCheckNAdd(6); break; case 7: if (curChar == 91 && kind > 132) kind = 132; break; case 11: if (curChar == 93 && kind > 129) kind = 129; break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 0: case 6: if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) break; if (kind > 131) kind = 131; jjCheckNAdd(6); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 13 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_1(int pos, long active0, long active1) { switch (pos) { case 0: if ((active1 & 0x180L) != 0L) { jjmatchedKind = 70; return -1; } return -1; default : return -1; } } private final int jjStartNfa_1(int pos, long active0, long active1) { return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0, active1), pos + 1); } private final int jjStopAtPos(int pos, int kind) { jjmatchedKind = kind; jjmatchedPos = pos; return pos + 1; } private final int jjStartNfaWithStates_1(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_1(state, pos + 1); } private final int jjMoveStringLiteralDfa0_1() { switch(curChar) { case 35: return jjMoveStringLiteralDfa1_1(0x100L); case 36: return jjMoveStringLiteralDfa1_1(0x80L); default : return jjMoveNfa_1(2, 0); } } private final int jjMoveStringLiteralDfa1_1(long active1) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_1(0, 0L, active1); return 1; } switch(curChar) { case 123: if ((active1 & 0x80L) != 0L) return jjStopAtPos(1, 71); else if ((active1 & 0x100L) != 0L) return jjStopAtPos(1, 72); break; default : break; } return jjStartNfa_1(0, 0L, active1); } private final int jjMoveNfa_1(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 3; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 2: if ((0xefffffe6ffffd9ffL & l) != 0L) { if (kind > 69) kind = 69; jjCheckNAdd(1); } else if ((0x100002600L & l) != 0L) { if (kind > 68) kind = 68; jjCheckNAdd(0); } else if ((0x1000001800000000L & l) != 0L) { if (kind > 70) kind = 70; } break; case 0: if ((0x100002600L & l) == 0L) break; kind = 68; jjCheckNAdd(0); break; case 1: if ((0xefffffe6ffffd9ffL & l) == 0L) break; kind = 69; jjCheckNAdd(1); break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 2: if ((0xf7fffffff7ffffffL & l) != 0L) { if (kind > 69) kind = 69; jjCheckNAdd(1); } else if ((0x800000008000000L & l) != 0L) { if (kind > 70) kind = 70; } break; case 1: if ((0xf7fffffff7ffffffL & l) == 0L) break; kind = 69; jjCheckNAdd(1); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 2: case 1: if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) break; if (kind > 69) kind = 69; jjCheckNAdd(1); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_0(int pos, long active0, long active1) { switch (pos) { case 0: if ((active1 & 0x180L) != 0L) { jjmatchedKind = 70; return -1; } return -1; default : return -1; } } private final int jjStartNfa_0(int pos, long active0, long active1) { return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0, active1), pos + 1); } private final int jjStartNfaWithStates_0(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_0(state, pos + 1); } private final int jjMoveStringLiteralDfa0_0() { switch(curChar) { case 35: return jjMoveStringLiteralDfa1_0(0x100L); case 36: return jjMoveStringLiteralDfa1_0(0x80L); default : return jjMoveNfa_0(2, 0); } } private final int jjMoveStringLiteralDfa1_0(long active1) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_0(0, 0L, active1); return 1; } switch(curChar) { case 123: if ((active1 & 0x80L) != 0L) return jjStopAtPos(1, 71); else if ((active1 & 0x100L) != 0L) return jjStopAtPos(1, 72); break; default : break; } return jjStartNfa_0(0, 0L, active1); } static final long[] jjbitVec3 = { 0x1ff00000fffffffeL, 0xffffffffffffc000L, 0xffffffffL, 0x600000000000000L }; static final long[] jjbitVec4 = { 0x0L, 0x0L, 0x0L, 0xff7fffffff7fffffL }; static final long[] jjbitVec5 = { 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL }; static final long[] jjbitVec6 = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffL, 0x0L }; static final long[] jjbitVec7 = { 0xffffffffffffffffL, 0xffffffffffffffffL, 0x0L, 0x0L }; static final long[] jjbitVec8 = { 0x3fffffffffffL, 0x0L, 0x0L, 0x0L }; private final int jjMoveNfa_0(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 567; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 2: if ((0xefffffe6ffffd9ffL & l) != 0L) { if (kind > 69) kind = 69; jjCheckNAdd(1); } else if ((0x100002600L & l) != 0L) { if (kind > 68) kind = 68; jjCheckNAdd(0); } else if ((0x1000001800000000L & l) != 0L) { if (kind > 70) kind = 70; } if (curChar == 60) jjAddStates(7, 8); if (curChar == 60) jjCheckNAddStates(9, 84); if (curChar == 60) jjCheckNAddStates(85, 125); break; case 0: if ((0x100002600L & l) == 0L) break; if (kind > 68) kind = 68; jjCheckNAdd(0); break; case 1: if ((0xefffffe6ffffd9ffL & l) == 0L) break; if (kind > 69) kind = 69; jjCheckNAdd(1); break; case 3: if (curChar == 60) jjCheckNAddStates(85, 125); break; case 5: if ((0x100002600L & l) != 0L) jjAddStates(126, 127); break; case 6: if (curChar == 62 && kind > 6) kind = 6; break; case 14: if ((0x100002600L & l) != 0L) jjAddStates(128, 129); break; case 15: if (curChar == 62 && kind > 7) kind = 7; break; case 23: if ((0x100002600L & l) != 0L && kind > 8) kind = 8; break; case 26: if ((0x100002600L & l) != 0L && kind > 9) kind = 9; break; case 33: if ((0x100002600L & l) != 0L && kind > 10) kind = 10; break; case 38: if ((0x100002600L & l) != 0L && kind > 11) kind = 11; break; case 46: if ((0x100002600L & l) != 0L && kind > 12) kind = 12; break; case 53: if ((0x100002600L & l) != 0L && kind > 13) kind = 13; break; case 58: if ((0x100002600L & l) != 0L && kind > 14) kind = 14; break; case 65: if ((0x100002600L & l) != 0L && kind > 15) kind = 15; break; case 72: if ((0x100002600L & l) != 0L && kind > 16) kind = 16; break; case 78: if ((0x100002600L & l) != 0L && kind > 17) kind = 17; break; case 86: if ((0x100002600L & l) != 0L && kind > 18) kind = 18; break; case 93: if ((0x100002600L & l) != 0L && kind > 19) kind = 19; break; case 102: if ((0x100002600L & l) != 0L && kind > 20) kind = 20; break; case 108: if ((0x100002600L & l) != 0L && kind > 21) kind = 21; break; case 118: if ((0x100002600L & l) != 0L && kind > 22) kind = 22; break; case 124: if ((0x100002600L & l) != 0L && kind > 23) kind = 23; break; case 129: if ((0x100002600L & l) != 0L && kind > 24) kind = 24; break; case 136: if ((0x100002600L & l) != 0L && kind > 25) kind = 25; break; case 141: if ((0x100002600L & l) != 0L && kind > 26) kind = 26; break; case 149: if ((0x100002600L & l) != 0L) jjAddStates(130, 131); break; case 150: if (curChar == 62 && kind > 27) kind = 27; break; case 159: if ((0x100002600L & l) != 0L) jjAddStates(132, 133); break; case 160: if (curChar == 62 && kind > 28) kind = 28; break; case 168: if ((0x100002600L & l) != 0L) jjAddStates(134, 135); break; case 169: if (curChar == 62 && kind > 30) kind = 30; break; case 177: if ((0x100002600L & l) != 0L) jjCheckNAddStates(136, 138); break; case 178: if (curChar == 47) jjCheckNAdd(179); break; case 179: if (curChar == 62 && kind > 44) kind = 44; break; case 184: if ((0x100002600L & l) != 0L) jjCheckNAddStates(139, 141); break; case 185: if (curChar == 47) jjCheckNAdd(186); break; case 186: if (curChar == 62 && kind > 45) kind = 45; break; case 192: if ((0x100002600L & l) != 0L) jjCheckNAddStates(142, 144); break; case 193: if (curChar == 47) jjCheckNAdd(194); break; case 194: if (curChar == 62 && kind > 46) kind = 46; break; case 201: if ((0x100002600L & l) != 0L) jjCheckNAddStates(145, 147); break; case 202: if (curChar == 47) jjCheckNAdd(203); break; case 203: if (curChar == 62 && kind > 47) kind = 47; break; case 208: if ((0x100002600L & l) != 0L) jjCheckNAddStates(148, 150); break; case 209: if (curChar == 47) jjCheckNAdd(210); break; case 210: if (curChar == 62 && kind > 48) kind = 48; break; case 216: if ((0x100002600L & l) != 0L) jjCheckNAddStates(151, 153); break; case 217: if (curChar == 47) jjCheckNAdd(218); break; case 218: if (curChar == 62 && kind > 49) kind = 49; break; case 220: if ((0x100002600L & l) != 0L) jjCheckNAddStates(154, 156); break; case 221: if (curChar == 47) jjCheckNAdd(222); break; case 222: if (curChar == 62 && kind > 50) kind = 50; break; case 225: if ((0x100002600L & l) != 0L) jjCheckNAddStates(157, 159); break; case 226: if (curChar == 47) jjCheckNAdd(227); break; case 227: if (curChar == 62 && kind > 51) kind = 51; break; case 230: if ((0x100002600L & l) != 0L) jjCheckNAddStates(160, 162); break; case 231: if (curChar == 47) jjCheckNAdd(232); break; case 232: if (curChar == 62 && kind > 52) kind = 52; break; case 235: if ((0x100002600L & l) != 0L) jjAddStates(163, 164); break; case 236: if (curChar == 62 && kind > 53) kind = 53; break; case 244: if ((0x100002600L & l) != 0L) jjCheckNAddStates(165, 167); break; case 245: if (curChar == 47) jjCheckNAdd(246); break; case 246: if (curChar == 62 && kind > 54) kind = 54; break; case 253: if ((0x100002600L & l) != 0L && kind > 55) kind = 55; break; case 260: if ((0x100002600L & l) != 0L) jjCheckNAddStates(168, 170); break; case 261: if (curChar == 47) jjCheckNAdd(262); break; case 262: if (curChar == 62 && kind > 56) kind = 56; break; case 270: if ((0x100002600L & l) != 0L && kind > 57) kind = 57; break; case 278: if ((0x100002600L & l) != 0L) jjCheckNAddStates(171, 173); break; case 279: if (curChar == 47) jjCheckNAdd(280); break; case 280: if (curChar == 62 && kind > 58) kind = 58; break; case 289: if ((0x100002600L & l) != 0L && kind > 59) kind = 59; break; case 296: if ((0x100002600L & l) != 0L) jjAddStates(174, 175); break; case 297: if (curChar == 62 && kind > 61) kind = 61; break; case 305: if (curChar == 60) jjCheckNAddStates(9, 84); break; case 306: if (curChar == 35) jjCheckNAdd(12); break; case 307: if (curChar == 35) jjCheckNAdd(21); break; case 308: if (curChar == 35) jjCheckNAdd(24); break; case 309: if (curChar == 35) jjCheckNAdd(31); break; case 310: if (curChar == 35) jjCheckNAdd(36); break; case 311: if (curChar == 35) jjCheckNAdd(44); break; case 312: if (curChar == 35) jjCheckNAdd(51); break; case 313: if (curChar == 35) jjCheckNAdd(56); break; case 314: if (curChar == 35) jjCheckNAdd(63); break; case 315: if (curChar == 35) jjCheckNAdd(70); break; case 316: if (curChar == 35) jjCheckNAdd(76); break; case 317: if (curChar == 35) jjCheckNAdd(84); break; case 318: if (curChar == 35) jjCheckNAdd(91); break; case 319: if (curChar == 35) jjCheckNAdd(100); break; case 320: if (curChar == 35) jjCheckNAdd(106); break; case 321: if (curChar == 35) jjCheckNAdd(116); break; case 322: if (curChar == 35) jjCheckNAdd(122); break; case 323: if (curChar == 35) jjCheckNAdd(127); break; case 324: if (curChar == 35) jjCheckNAdd(134); break; case 325: if (curChar == 35) jjCheckNAdd(139); break; case 326: if (curChar == 35) jjCheckNAdd(147); break; case 327: if (curChar == 35) jjCheckNAdd(157); break; case 328: if (curChar == 35) jjCheckNAdd(166); break; case 329: if (curChar == 35) jjCheckNAdd(175); break; case 330: if (curChar == 47) jjCheckNAdd(334); break; case 332: if ((0x100002600L & l) != 0L) jjAddStates(176, 177); break; case 333: if (curChar == 62 && kind > 31) kind = 31; break; case 335: if (curChar == 35) jjCheckNAdd(334); break; case 336: case 532: if (curChar == 47) jjCheckNAdd(335); break; case 337: if (curChar == 47) jjCheckNAdd(343); break; case 339: if ((0x100002600L & l) != 0L) jjAddStates(178, 179); break; case 340: if (curChar == 62 && kind > 32) kind = 32; break; case 344: if (curChar == 35) jjCheckNAdd(343); break; case 345: case 533: if (curChar == 47) jjCheckNAdd(344); break; case 346: if (curChar == 47) jjCheckNAdd(355); break; case 348: if ((0x100002600L & l) != 0L) jjAddStates(180, 181); break; case 349: if (curChar == 62 && kind > 33) kind = 33; break; case 356: if (curChar == 35) jjCheckNAdd(355); break; case 357: case 534: if (curChar == 47) jjCheckNAdd(356); break; case 358: if (curChar == 47) jjCheckNAdd(367); break; case 360: if ((0x100002600L & l) != 0L) jjAddStates(182, 183); break; case 361: if (curChar == 62 && kind > 34) kind = 34; break; case 368: if (curChar == 35) jjCheckNAdd(367); break; case 369: case 535: if (curChar == 47) jjCheckNAdd(368); break; case 370: if (curChar == 47) jjCheckNAdd(379); break; case 372: if ((0x100002600L & l) != 0L) jjAddStates(184, 185); break; case 373: if (curChar == 62 && kind > 35) kind = 35; break; case 380: if (curChar == 35) jjCheckNAdd(379); break; case 381: case 536: if (curChar == 47) jjCheckNAdd(380); break; case 382: if (curChar == 47) jjCheckNAdd(389); break; case 384: if ((0x100002600L & l) != 0L) jjAddStates(186, 187); break; case 385: if (curChar == 62 && kind > 36) kind = 36; break; case 390: if (curChar == 35) jjCheckNAdd(389); break; case 391: case 537: if (curChar == 47) jjCheckNAdd(390); break; case 392: if (curChar == 47) jjCheckNAdd(400); break; case 394: if ((0x100002600L & l) != 0L) jjAddStates(188, 189); break; case 395: if (curChar == 62 && kind > 37) kind = 37; break; case 401: if (curChar == 35) jjCheckNAdd(400); break; case 402: case 538: if (curChar == 47) jjCheckNAdd(401); break; case 403: if (curChar == 47) jjCheckNAdd(411); break; case 405: if ((0x100002600L & l) != 0L) jjAddStates(190, 191); break; case 406: if (curChar == 62 && kind > 38) kind = 38; break; case 412: if (curChar == 35) jjCheckNAdd(411); break; case 413: case 539: if (curChar == 47) jjCheckNAdd(412); break; case 414: if (curChar == 47) jjCheckNAdd(424); break; case 416: if ((0x100002600L & l) != 0L) jjAddStates(192, 193); break; case 417: if (curChar == 62 && kind > 39) kind = 39; break; case 425: if (curChar == 35) jjCheckNAdd(424); break; case 426: case 540: if (curChar == 47) jjCheckNAdd(425); break; case 427: if (curChar == 47) jjCheckNAdd(434); break; case 429: if ((0x100002600L & l) != 0L) jjAddStates(194, 195); break; case 430: if (curChar == 62 && kind > 40) kind = 40; break; case 435: if (curChar == 35) jjCheckNAdd(434); break; case 436: case 541: if (curChar == 47) jjCheckNAdd(435); break; case 437: if (curChar == 47) jjCheckNAdd(447); break; case 439: if ((0x100002600L & l) != 0L) jjAddStates(196, 197); break; case 440: if (curChar == 62 && kind > 41) kind = 41; break; case 448: if (curChar == 35) jjCheckNAdd(447); break; case 449: case 542: if (curChar == 47) jjCheckNAdd(448); break; case 450: if (curChar == 47) jjCheckNAdd(461); break; case 452: if ((0x100002600L & l) != 0L) jjAddStates(198, 199); break; case 453: if (curChar == 62 && kind > 42) kind = 42; break; case 462: if (curChar == 35) jjCheckNAdd(461); break; case 463: case 543: if (curChar == 47) jjCheckNAdd(462); break; case 464: if (curChar == 47) jjCheckNAdd(472); break; case 466: if ((0x100002600L & l) != 0L) jjAddStates(200, 201); break; case 467: if (curChar == 62 && kind > 43) kind = 43; break; case 473: if (curChar == 35) jjCheckNAdd(472); break; case 474: case 544: if (curChar == 47) jjCheckNAdd(473); break; case 475: if (curChar == 35) jjCheckNAdd(182); break; case 476: if (curChar == 35) jjCheckNAdd(190); break; case 477: if (curChar == 35) jjCheckNAdd(199); break; case 478: if (curChar == 35) jjCheckNAdd(206); break; case 479: if (curChar == 35) jjCheckNAdd(214); break; case 480: if (curChar == 35) jjCheckNAdd(215); break; case 481: if (curChar == 35) jjCheckNAdd(223); break; case 482: if (curChar == 35) jjCheckNAdd(228); break; case 483: if (curChar == 35) jjCheckNAdd(233); break; case 484: if (curChar == 35) jjCheckNAdd(242); break; case 485: if (curChar == 35) jjCheckNAdd(251); break; case 486: if (curChar == 35) jjCheckNAdd(258); break; case 487: if (curChar == 35) jjCheckNAdd(268); break; case 488: if (curChar == 35) jjCheckNAdd(276); break; case 489: if (curChar == 35) jjCheckNAdd(287); break; case 490: if (curChar == 35) jjCheckNAdd(294); break; case 491: if (curChar == 47) jjCheckNAdd(499); break; case 493: if ((0x100002600L & l) != 0L) jjAddStates(202, 203); break; case 494: if (curChar == 62 && kind > 60) kind = 60; break; case 500: if (curChar == 35) jjCheckNAdd(499); break; case 501: case 545: if (curChar == 47) jjCheckNAdd(500); break; case 502: if (curChar == 35) jjCheckNAdd(304); break; case 503: if (curChar == 47) jjCheckNAdd(513); break; case 505: if ((0x100002600L & l) != 0L) jjAddStates(204, 205); break; case 506: if (curChar == 62 && kind > 62) kind = 62; break; case 514: if (curChar == 35) jjCheckNAdd(513); break; case 515: case 546: if (curChar == 47) jjCheckNAdd(514); break; case 518: if ((0x100002600L & l) != 0L && kind > 65) kind = 65; break; case 521: if (curChar == 35) jjstateSet[jjnewStateCnt++] = 520; break; case 523: if (curChar == 47) jjstateSet[jjnewStateCnt++] = 524; break; case 524: if (curChar == 62 && kind > 66) kind = 66; break; case 527: if (curChar == 35) jjstateSet[jjnewStateCnt++] = 526; break; case 528: if (curChar == 35) jjstateSet[jjnewStateCnt++] = 529; break; case 530: case 553: if (curChar == 47) jjCheckNAdd(528); break; case 549: if (curChar == 35) jjstateSet[jjnewStateCnt++] = 548; break; case 552: if (curChar == 35) jjstateSet[jjnewStateCnt++] = 551; break; case 554: if (curChar == 60) jjAddStates(7, 8); break; case 555: if (curChar == 45 && kind > 29) kind = 29; break; case 556: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 555; break; case 557: if (curChar == 35) jjstateSet[jjnewStateCnt++] = 556; break; case 559: if (curChar == 36) jjCheckNAddStates(206, 209); break; case 560: if ((0x3ff001000000000L & l) != 0L) jjCheckNAddStates(206, 209); break; case 561: if (curChar == 46) jjstateSet[jjnewStateCnt++] = 562; break; case 562: if (curChar == 36) jjCheckNAddStates(210, 213); break; case 563: if ((0x3ff001000000000L & l) != 0L) jjCheckNAddStates(210, 213); break; case 564: if ((0x100002600L & l) != 0L) jjCheckNAddTwoStates(564, 565); break; case 565: if (curChar == 62 && kind > 64) kind = 64; break; case 566: if (curChar == 47) jjstateSet[jjnewStateCnt++] = 558; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 2: if ((0xf7fffffff7ffffffL & l) != 0L) { if (kind > 69) kind = 69; jjCheckNAdd(1); } else if ((0x800000008000000L & l) != 0L) { if (kind > 70) kind = 70; } if (curChar == 91) jjAddStates(7, 8); if (curChar == 91) jjAddStates(214, 274); break; case 1: if ((0xf7fffffff7ffffffL & l) == 0L) break; if (kind > 69) kind = 69; jjCheckNAdd(1); break; case 4: if (curChar == 116) jjAddStates(126, 127); break; case 6: if (curChar == 93 && kind > 6) kind = 6; break; case 7: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 4; break; case 8: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 7; break; case 9: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 8; break; case 10: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 9; break; case 11: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 10; break; case 12: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 11; break; case 13: if (curChar == 114) jjAddStates(128, 129); break; case 15: if (curChar == 93 && kind > 7) kind = 7; break; case 16: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 13; break; case 17: if (curChar == 118) jjstateSet[jjnewStateCnt++] = 16; break; case 18: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 17; break; case 19: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 18; break; case 20: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 19; break; case 21: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 20; break; case 22: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 23; break; case 24: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 22; break; case 25: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 26; break; case 27: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 25; break; case 28: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 27; break; case 29: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 28; break; case 30: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 29; break; case 31: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 30; break; case 32: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 33; break; case 34: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 32; break; case 35: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 34; break; case 36: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 35; break; case 37: if (curChar == 104) jjstateSet[jjnewStateCnt++] = 38; break; case 39: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 37; break; case 40: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 39; break; case 41: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 40; break; case 42: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 41; break; case 43: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 42; break; case 44: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 43; break; case 45: if (curChar == 104) jjstateSet[jjnewStateCnt++] = 46; break; case 47: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 45; break; case 48: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 47; break; case 49: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 48; break; case 50: if (curChar == 119) jjstateSet[jjnewStateCnt++] = 49; break; case 51: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 50; break; case 52: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 53; break; case 54: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 52; break; case 55: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 54; break; case 56: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 55; break; case 57: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 58; break; case 59: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 57; break; case 60: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 59; break; case 61: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 60; break; case 62: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 61; break; case 63: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 62; break; case 64: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 65; break; case 66: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 64; break; case 67: if (curChar == 98) jjstateSet[jjnewStateCnt++] = 66; break; case 68: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 67; break; case 69: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 68; break; case 70: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 69; break; case 71: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 72; break; case 73: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 71; break; case 74: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 73; break; case 75: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 74; break; case 76: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 75; break; case 77: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 78; break; case 79: if (curChar == 100) jjstateSet[jjnewStateCnt++] = 77; break; case 80: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 79; break; case 81: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 80; break; case 82: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 81; break; case 83: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 82; break; case 84: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 83; break; case 85: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 86; break; case 87: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 85; break; case 88: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 87; break; case 89: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 88; break; case 90: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 89; break; case 91: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 90; break; case 92: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 93; break; case 94: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 92; break; case 95: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 94; break; case 96: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 95; break; case 97: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 96; break; case 98: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 97; break; case 99: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 98; break; case 100: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 99; break; case 101: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 102; break; case 103: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 101; break; case 104: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 103; break; case 105: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 104; break; case 106: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 105; break; case 107: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 108; break; case 109: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 107; break; case 110: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 109; break; case 111: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 110; break; case 112: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 111; break; case 113: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 112; break; case 114: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 113; break; case 115: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 114; break; case 116: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 115; break; case 117: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 118; break; case 119: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 117; break; case 120: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 119; break; case 121: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 120; break; case 122: if (curChar == 118) jjstateSet[jjnewStateCnt++] = 121; break; case 123: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 124; break; case 125: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 123; break; case 126: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 125; break; case 127: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 126; break; case 128: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 129; break; case 130: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 128; break; case 131: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 130; break; case 132: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 131; break; case 133: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 132; break; case 134: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 133; break; case 135: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 136; break; case 137: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 135; break; case 138: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 137; break; case 139: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 138; break; case 140: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 141; break; case 142: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 140; break; case 143: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 142; break; case 144: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 143; break; case 145: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 144; break; case 146: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 145; break; case 147: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 146; break; case 148: if (curChar == 115) jjAddStates(130, 131); break; case 150: if (curChar == 93 && kind > 27) kind = 27; break; case 151: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 148; break; case 152: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 151; break; case 153: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 152; break; case 154: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 153; break; case 155: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 154; break; case 156: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 155; break; case 157: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 156; break; case 158: if (curChar == 116) jjAddStates(132, 133); break; case 160: if (curChar == 93 && kind > 28) kind = 28; break; case 161: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 158; break; case 162: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 161; break; case 163: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 162; break; case 164: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 163; break; case 165: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 164; break; case 166: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 165; break; case 167: if (curChar == 101) jjAddStates(134, 135); break; case 169: if (curChar == 93 && kind > 30) kind = 30; break; case 170: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 167; break; case 171: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 170; break; case 172: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 171; break; case 173: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 172; break; case 174: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 173; break; case 175: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 174; break; case 176: if (curChar == 101) jjAddStates(136, 138); break; case 179: if (curChar == 93 && kind > 44) kind = 44; break; case 180: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 176; break; case 181: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 180; break; case 182: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 181; break; case 183: if (curChar == 107) jjAddStates(139, 141); break; case 186: if (curChar == 93 && kind > 45) kind = 45; break; case 187: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 183; break; case 188: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 187; break; case 189: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 188; break; case 190: if (curChar == 98) jjstateSet[jjnewStateCnt++] = 189; break; case 191: if (curChar == 110) jjAddStates(142, 144); break; case 194: if (curChar == 93 && kind > 46) kind = 46; break; case 195: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 191; break; case 196: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 195; break; case 197: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 196; break; case 198: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 197; break; case 199: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 198; break; case 200: if (curChar == 112) jjAddStates(145, 147); break; case 203: if (curChar == 93 && kind > 47) kind = 47; break; case 204: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 200; break; case 205: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 204; break; case 206: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 205; break; case 207: if (curChar == 104) jjAddStates(148, 150); break; case 210: if (curChar == 93 && kind > 48) kind = 48; break; case 211: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 207; break; case 212: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 211; break; case 213: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 212; break; case 214: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 213; break; case 215: if (curChar == 116) jjAddStates(151, 153); break; case 218: if (curChar == 93 && kind > 49) kind = 49; break; case 219: if (curChar == 116) jjAddStates(154, 156); break; case 222: if (curChar == 93 && kind > 50) kind = 50; break; case 223: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 219; break; case 224: if (curChar == 116) jjAddStates(157, 159); break; case 227: if (curChar == 93 && kind > 51) kind = 51; break; case 228: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 224; break; case 229: if (curChar == 116) jjAddStates(160, 162); break; case 232: if (curChar == 93 && kind > 52) kind = 52; break; case 233: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 229; break; case 234: if (curChar == 116) jjAddStates(163, 164); break; case 236: if (curChar == 93 && kind > 53) kind = 53; break; case 237: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 234; break; case 238: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 237; break; case 239: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 238; break; case 240: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 239; break; case 241: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 240; break; case 242: if (curChar == 100) jjstateSet[jjnewStateCnt++] = 241; break; case 243: if (curChar == 100) jjAddStates(165, 167); break; case 246: if (curChar == 93 && kind > 54) kind = 54; break; case 247: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 243; break; case 248: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 247; break; case 249: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 248; break; case 250: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 249; break; case 251: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 250; break; case 252: if (curChar == 100) jjstateSet[jjnewStateCnt++] = 253; break; case 254: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 252; break; case 255: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 254; break; case 256: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 255; break; case 257: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 256; break; case 258: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 257; break; case 259: if (curChar == 101) jjAddStates(168, 170); break; case 262: if (curChar == 93 && kind > 56) kind = 56; break; case 263: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 259; break; case 264: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 263; break; case 265: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 264; break; case 266: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 265; break; case 267: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 266; break; case 268: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 267; break; case 269: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 270; break; case 271: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 269; break; case 272: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 271; break; case 273: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 272; break; case 274: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 273; break; case 275: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 274; break; case 276: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 275; break; case 277: if (curChar == 107) jjAddStates(171, 173); break; case 280: if (curChar == 93 && kind > 58) kind = 58; break; case 281: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 277; break; case 282: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 281; break; case 283: if (curChar == 98) jjstateSet[jjnewStateCnt++] = 282; break; case 284: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 283; break; case 285: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 284; break; case 286: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 285; break; case 287: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 286; break; case 288: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 289; break; case 290: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 288; break; case 291: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 290; break; case 292: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 291; break; case 293: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 292; break; case 294: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 293; break; case 295: if (curChar == 101) jjAddStates(174, 175); break; case 297: if (curChar == 93 && kind > 61) kind = 61; break; case 298: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 295; break; case 299: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 298; break; case 300: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 299; break; case 301: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 300; break; case 302: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 301; break; case 303: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 302; break; case 304: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 303; break; case 331: if (curChar == 102) jjAddStates(176, 177); break; case 333: if (curChar == 93 && kind > 31) kind = 31; break; case 334: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 331; break; case 338: if (curChar == 116) jjAddStates(178, 179); break; case 340: if (curChar == 93 && kind > 32) kind = 32; break; case 341: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 338; break; case 342: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 341; break; case 343: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 342; break; case 347: if (curChar == 114) jjAddStates(180, 181); break; case 349: if (curChar == 93 && kind > 33) kind = 33; break; case 350: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 347; break; case 351: if (curChar == 118) jjstateSet[jjnewStateCnt++] = 350; break; case 352: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 351; break; case 353: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 352; break; case 354: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 353; break; case 355: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 354; break; case 359: if (curChar == 116) jjAddStates(182, 183); break; case 361: if (curChar == 93 && kind > 34) kind = 34; break; case 362: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 359; break; case 363: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 362; break; case 364: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 363; break; case 365: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 364; break; case 366: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 365; break; case 367: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 366; break; case 371: if (curChar == 104) jjAddStates(184, 185); break; case 373: if (curChar == 93 && kind > 35) kind = 35; break; case 374: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 371; break; case 375: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 374; break; case 376: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 375; break; case 377: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 376; break; case 378: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 377; break; case 379: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 378; break; case 383: if (curChar == 108) jjAddStates(186, 187); break; case 385: if (curChar == 93 && kind > 36) kind = 36; break; case 386: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 383; break; case 387: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 386; break; case 388: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 387; break; case 389: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 388; break; case 393: if (curChar == 108) jjAddStates(188, 189); break; case 395: if (curChar == 93 && kind > 37) kind = 37; break; case 396: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 393; break; case 397: if (curChar == 98) jjstateSet[jjnewStateCnt++] = 396; break; case 398: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 397; break; case 399: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 398; break; case 400: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 399; break; case 404: if (curChar == 110) jjAddStates(190, 191); break; case 406: if (curChar == 93 && kind > 38) kind = 38; break; case 407: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 404; break; case 408: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 407; break; case 409: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 408; break; case 410: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 409; break; case 411: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 410; break; case 415: if (curChar == 110) jjAddStates(192, 193); break; case 417: if (curChar == 93 && kind > 39) kind = 39; break; case 418: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 415; break; case 419: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 418; break; case 420: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 419; break; case 421: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 420; break; case 422: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 421; break; case 423: if (curChar == 117) jjstateSet[jjnewStateCnt++] = 422; break; case 424: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 423; break; case 428: if (curChar == 111) jjAddStates(194, 195); break; case 430: if (curChar == 93 && kind > 40) kind = 40; break; case 431: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 428; break; case 432: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 431; break; case 433: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 432; break; case 434: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 433; break; case 438: if (curChar == 115) jjAddStates(196, 197); break; case 440: if (curChar == 93 && kind > 41) kind = 41; break; case 441: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 438; break; case 442: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 441; break; case 443: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 442; break; case 444: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 443; break; case 445: if (curChar == 109) jjstateSet[jjnewStateCnt++] = 444; break; case 446: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 445; break; case 447: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 446; break; case 451: if (curChar == 109) jjAddStates(198, 199); break; case 453: if (curChar == 93 && kind > 42) kind = 42; break; case 454: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 451; break; case 455: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 454; break; case 456: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 455; break; case 457: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 456; break; case 458: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 457; break; case 459: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 458; break; case 460: if (curChar == 114) jjstateSet[jjnewStateCnt++] = 459; break; case 461: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 460; break; case 465: if (curChar == 104) jjAddStates(200, 201); break; case 467: if (curChar == 93 && kind > 43) kind = 43; break; case 468: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 465; break; case 469: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 468; break; case 470: if (curChar == 105) jjstateSet[jjnewStateCnt++] = 469; break; case 471: if (curChar == 119) jjstateSet[jjnewStateCnt++] = 470; break; case 472: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 471; break; case 492: if (curChar == 101) jjAddStates(202, 203); break; case 494: if (curChar == 93 && kind > 60) kind = 60; break; case 495: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 492; break; case 496: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 495; break; case 497: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 496; break; case 498: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 497; break; case 499: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 498; break; case 504: if (curChar == 101) jjAddStates(204, 205); break; case 506: if (curChar == 93 && kind > 62) kind = 62; break; case 507: if (curChar == 112) jjstateSet[jjnewStateCnt++] = 504; break; case 508: if (curChar == 97) jjstateSet[jjnewStateCnt++] = 507; break; case 509: if (curChar == 99) jjstateSet[jjnewStateCnt++] = 508; break; case 510: if (curChar == 115) jjstateSet[jjnewStateCnt++] = 509; break; case 511: if (curChar == 101) jjstateSet[jjnewStateCnt++] = 510; break; case 512: if (curChar == 111) jjstateSet[jjnewStateCnt++] = 511; break; case 513: if (curChar == 110) jjstateSet[jjnewStateCnt++] = 512; break; case 516: if (curChar == 64 && kind > 63) kind = 63; break; case 517: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 518; break; case 519: case 547: if (curChar == 116) jjCheckNAdd(517); break; case 520: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 519; break; case 522: if (curChar == 108) jjAddStates(275, 276); break; case 524: if (curChar == 93 && kind > 66) kind = 66; break; case 525: case 550: if (curChar == 116) jjCheckNAdd(522); break; case 526: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 525; break; case 529: if ((0x7fffffe87fffffeL & l) == 0L) break; if (kind > 67) kind = 67; jjstateSet[jjnewStateCnt++] = 529; break; case 531: if (curChar == 91) jjAddStates(214, 274); break; case 548: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 547; break; case 551: if (curChar == 102) jjstateSet[jjnewStateCnt++] = 550; break; case 554: if (curChar == 91) jjAddStates(7, 8); break; case 558: if (curChar == 64) jjCheckNAddStates(277, 279); break; case 559: case 560: if ((0x7fffffe87ffffffL & l) != 0L) jjCheckNAddStates(206, 209); break; case 562: case 563: if ((0x7fffffe87ffffffL & l) != 0L) jjCheckNAddStates(210, 213); break; case 565: if (curChar == 93 && kind > 64) kind = 64; break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 2: case 1: if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) break; if (kind > 69) kind = 69; jjCheckNAdd(1); break; case 559: case 560: if (jjCanMove_1(hiByte, i1, i2, l1, l2)) jjCheckNAddStates(206, 209); break; case 562: case 563: if (jjCanMove_1(hiByte, i1, i2, l1, l2)) jjCheckNAddStates(210, 213); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 567 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_2(int pos, long active0, long active1) { switch (pos) { case 0: if ((active1 & 0x800000000000L) != 0L) return 2; if ((active1 & 0xe0000000180000L) != 0L) { jjmatchedKind = 120; return 34; } if ((active1 & 0x8000000000L) != 0L) return 36; return -1; case 1: if ((active1 & 0x60000000000000L) != 0L) return 34; if ((active1 & 0x80000000180000L) != 0L) { if (jjmatchedPos != 1) { jjmatchedKind = 120; jjmatchedPos = 1; } return 34; } return -1; case 2: if ((active1 & 0x80000000180000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 2; return 34; } return -1; case 3: if ((active1 & 0x100000L) != 0L) return 34; if ((active1 & 0x80000000080000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 3; return 34; } return -1; default : return -1; } } private final int jjStartNfa_2(int pos, long active0, long active1) { return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0, active1), pos + 1); } private final int jjStartNfaWithStates_2(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_2(state, pos + 1); } private final int jjMoveStringLiteralDfa0_2() { switch(curChar) { case 33: jjmatchedKind = 107; return jjMoveStringLiteralDfa1_2(0x20000000L); case 37: return jjStopAtPos(0, 104); case 40: return jjStopAtPos(0, 113); case 41: return jjStopAtPos(0, 114); case 42: jjmatchedKind = 100; return jjMoveStringLiteralDfa1_2(0x2000000000L); case 43: return jjStopAtPos(0, 98); case 44: return jjStopAtPos(0, 108); case 45: return jjStopAtPos(0, 99); case 46: jjmatchedKind = 87; return jjMoveStringLiteralDfa1_2(0x4001000000L); case 47: return jjStartNfaWithStates_2(0, 103, 36); case 58: return jjStopAtPos(0, 110); case 59: return jjStopAtPos(0, 109); case 61: jjmatchedKind = 91; return jjMoveStringLiteralDfa1_2(0x10000000L); case 62: return jjStopAtPos(0, 123); case 63: jjmatchedKind = 89; return jjMoveStringLiteralDfa1_2(0x4000000L); case 91: return jjStartNfaWithStates_2(0, 111, 2); case 93: return jjStopAtPos(0, 112); case 97: return jjMoveStringLiteralDfa1_2(0x40000000000000L); case 102: return jjMoveStringLiteralDfa1_2(0x80000L); case 105: return jjMoveStringLiteralDfa1_2(0x20000000000000L); case 116: return jjMoveStringLiteralDfa1_2(0x100000L); case 117: return jjMoveStringLiteralDfa1_2(0x80000000000000L); case 123: return jjStopAtPos(0, 115); case 125: return jjStopAtPos(0, 116); default : return jjMoveNfa_2(1, 0); } } private final int jjMoveStringLiteralDfa1_2(long active1) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_2(0, 0L, active1); return 1; } switch(curChar) { case 42: if ((active1 & 0x2000000000L) != 0L) return jjStopAtPos(1, 101); break; case 46: if ((active1 & 0x1000000L) != 0L) { jjmatchedKind = 88; jjmatchedPos = 1; } return jjMoveStringLiteralDfa2_2(active1, 0x4000000000L); case 61: if ((active1 & 0x10000000L) != 0L) return jjStopAtPos(1, 92); else if ((active1 & 0x20000000L) != 0L) return jjStopAtPos(1, 93); break; case 63: if ((active1 & 0x4000000L) != 0L) return jjStopAtPos(1, 90); break; case 97: return jjMoveStringLiteralDfa2_2(active1, 0x80000L); case 110: if ((active1 & 0x20000000000000L) != 0L) return jjStartNfaWithStates_2(1, 117, 34); break; case 114: return jjMoveStringLiteralDfa2_2(active1, 0x100000L); case 115: if ((active1 & 0x40000000000000L) != 0L) return jjStartNfaWithStates_2(1, 118, 34); return jjMoveStringLiteralDfa2_2(active1, 0x80000000000000L); default : break; } return jjStartNfa_2(0, 0L, active1); } private final int jjMoveStringLiteralDfa2_2(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_2(0, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_2(1, 0L, active1); return 2; } switch(curChar) { case 46: if ((active1 & 0x4000000000L) != 0L) return jjStopAtPos(2, 102); break; case 105: return jjMoveStringLiteralDfa3_2(active1, 0x80000000000000L); case 108: return jjMoveStringLiteralDfa3_2(active1, 0x80000L); case 117: return jjMoveStringLiteralDfa3_2(active1, 0x100000L); default : break; } return jjStartNfa_2(1, 0L, active1); } private final int jjMoveStringLiteralDfa3_2(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_2(1, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_2(2, 0L, active1); return 3; } switch(curChar) { case 101: if ((active1 & 0x100000L) != 0L) return jjStartNfaWithStates_2(3, 84, 34); break; case 110: return jjMoveStringLiteralDfa4_2(active1, 0x80000000000000L); case 115: return jjMoveStringLiteralDfa4_2(active1, 0x80000L); default : break; } return jjStartNfa_2(2, 0L, active1); } private final int jjMoveStringLiteralDfa4_2(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_2(2, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_2(3, 0L, active1); return 4; } switch(curChar) { case 101: if ((active1 & 0x80000L) != 0L) return jjStartNfaWithStates_2(4, 83, 34); break; case 103: if ((active1 & 0x80000000000000L) != 0L) return jjStartNfaWithStates_2(4, 119, 34); break; default : break; } return jjStartNfa_2(3, 0L, active1); } private final int jjMoveNfa_2(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 73; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 36: if (curChar == 62 && kind > 124) kind = 124; break; case 1: if ((0x3ff000000000000L & l) != 0L) { if (kind > 85) kind = 85; jjCheckNAddStates(280, 282); } else if ((0x100002600L & l) != 0L) { if (kind > 73) kind = 73; jjCheckNAdd(0); } else if (curChar == 38) jjAddStates(283, 287); else if (curChar == 47) jjAddStates(288, 289); else if (curChar == 36) { if (kind > 120) kind = 120; jjCheckNAdd(34); } else if (curChar == 60) jjCheckNAdd(27); else if (curChar == 39) jjCheckNAddStates(290, 292); else if (curChar == 34) jjCheckNAddStates(293, 295); if (curChar == 38) { if (kind > 105) kind = 105; } else if (curChar == 60) { if (kind > 94) kind = 94; } if (curChar == 60) jjstateSet[jjnewStateCnt++] = 2; break; case 0: if ((0x100002600L & l) == 0L) break; if (kind > 73) kind = 73; jjCheckNAdd(0); break; case 2: if ((0xa00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 4; break; case 3: if (curChar == 45 && kind > 74) kind = 74; break; case 4: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 3; break; case 5: if (curChar == 34) jjCheckNAddStates(293, 295); break; case 6: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddStates(293, 295); break; case 8: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 9: if (curChar == 34 && kind > 81) kind = 81; break; case 11: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 12: if (curChar == 39) jjCheckNAddStates(290, 292); break; case 13: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddStates(290, 292); break; case 15: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 16: if (curChar == 39 && kind > 81) kind = 81; break; case 18: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 20: if (curChar == 34) jjCheckNAddTwoStates(21, 22); break; case 21: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddTwoStates(21, 22); break; case 22: if (curChar == 34 && kind > 82) kind = 82; break; case 23: if (curChar == 39) jjCheckNAddTwoStates(24, 25); break; case 24: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddTwoStates(24, 25); break; case 25: if (curChar == 39 && kind > 82) kind = 82; break; case 26: if (curChar == 60 && kind > 94) kind = 94; break; case 27: if (curChar == 61 && kind > 95) kind = 95; break; case 28: if (curChar == 60) jjCheckNAdd(27); break; case 29: case 70: if (curChar == 38 && kind > 105) kind = 105; break; case 33: if (curChar != 36) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 34: if ((0x3ff001000000000L & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 35: if (curChar == 47) jjAddStates(288, 289); break; case 38: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAddStates(280, 282); break; case 39: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAdd(39); break; case 40: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddTwoStates(40, 41); break; case 41: if (curChar == 46) jjCheckNAdd(42); break; case 42: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 86) kind = 86; jjCheckNAdd(42); break; case 56: if (curChar == 38) jjAddStates(283, 287); break; case 57: if (curChar == 59 && kind > 94) kind = 94; break; case 60: if (curChar == 59) jjCheckNAdd(27); break; case 63: if (curChar == 59 && kind > 96) kind = 96; break; case 66: if (curChar == 61 && kind > 97) kind = 97; break; case 67: if (curChar == 59) jjstateSet[jjnewStateCnt++] = 66; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 36: if (curChar == 93 && kind > 124) kind = 124; break; case 1: if ((0x7fffffe87ffffffL & l) != 0L) { if (kind > 120) kind = 120; jjCheckNAdd(34); } else if (curChar == 92) jjAddStates(296, 299); else if (curChar == 124) jjstateSet[jjnewStateCnt++] = 31; else if (curChar == 91) jjstateSet[jjnewStateCnt++] = 2; if (curChar == 103) jjCheckNAddTwoStates(51, 72); else if (curChar == 108) jjCheckNAddTwoStates(44, 46); else if (curChar == 124) { if (kind > 106) kind = 106; } else if (curChar == 114) jjAddStates(300, 301); break; case 6: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(293, 295); break; case 7: if (curChar == 92) jjAddStates(302, 303); break; case 8: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 10: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 11; break; case 11: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(293, 295); break; case 13: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(290, 292); break; case 14: if (curChar == 92) jjAddStates(304, 305); break; case 15: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 17: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 18; break; case 18: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(290, 292); break; case 19: if (curChar == 114) jjAddStates(300, 301); break; case 21: jjAddStates(306, 307); break; case 24: jjAddStates(308, 309); break; case 30: case 31: if (curChar == 124 && kind > 106) kind = 106; break; case 32: if (curChar == 124) jjstateSet[jjnewStateCnt++] = 31; break; case 33: case 34: if ((0x7fffffe87ffffffL & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 43: if (curChar == 108) jjCheckNAddTwoStates(44, 46); break; case 44: if (curChar == 116 && kind > 94) kind = 94; break; case 45: if (curChar == 101 && kind > 95) kind = 95; break; case 46: case 49: if (curChar == 116) jjCheckNAdd(45); break; case 47: if (curChar == 92) jjAddStates(296, 299); break; case 48: if (curChar == 108) jjCheckNAdd(44); break; case 50: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 49; break; case 51: if (curChar == 116 && kind > 96) kind = 96; break; case 52: if (curChar == 103) jjCheckNAdd(51); break; case 53: if (curChar == 101 && kind > 97) kind = 97; break; case 54: case 72: if (curChar == 116) jjCheckNAdd(53); break; case 55: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 54; break; case 58: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 57; break; case 59: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 58; break; case 61: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 60; break; case 62: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 61; break; case 64: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 63; break; case 65: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 64; break; case 68: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 67; break; case 69: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 68; break; case 71: if (curChar == 103) jjCheckNAddTwoStates(51, 72); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: case 34: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 6: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(293, 295); break; case 13: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(290, 292); break; case 21: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(306, 307); break; case 24: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(308, 309); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 73 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_3(int pos, long active0, long active1) { switch (pos) { case 0: if ((active1 & 0x800000000000L) != 0L) return 2; if ((active1 & 0xe0000000180000L) != 0L) { jjmatchedKind = 120; return 34; } return -1; case 1: if ((active1 & 0x60000000000000L) != 0L) return 34; if ((active1 & 0x80000000180000L) != 0L) { if (jjmatchedPos != 1) { jjmatchedKind = 120; jjmatchedPos = 1; } return 34; } return -1; case 2: if ((active1 & 0x80000000180000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 2; return 34; } return -1; case 3: if ((active1 & 0x100000L) != 0L) return 34; if ((active1 & 0x80000000080000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 3; return 34; } return -1; default : return -1; } } private final int jjStartNfa_3(int pos, long active0, long active1) { return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0, active1), pos + 1); } private final int jjStartNfaWithStates_3(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_3(state, pos + 1); } private final int jjMoveStringLiteralDfa0_3() { switch(curChar) { case 33: jjmatchedKind = 107; return jjMoveStringLiteralDfa1_3(0x20000000L); case 37: return jjStopAtPos(0, 104); case 40: return jjStopAtPos(0, 113); case 41: return jjStopAtPos(0, 114); case 42: jjmatchedKind = 100; return jjMoveStringLiteralDfa1_3(0x2000000000L); case 43: return jjStopAtPos(0, 98); case 44: return jjStopAtPos(0, 108); case 45: return jjStopAtPos(0, 99); case 46: jjmatchedKind = 87; return jjMoveStringLiteralDfa1_3(0x4001000000L); case 47: return jjStopAtPos(0, 103); case 58: return jjStopAtPos(0, 110); case 59: return jjStopAtPos(0, 109); case 61: jjmatchedKind = 91; return jjMoveStringLiteralDfa1_3(0x10000000L); case 62: jjmatchedKind = 125; return jjMoveStringLiteralDfa1_3(0x4000000000000000L); case 63: jjmatchedKind = 89; return jjMoveStringLiteralDfa1_3(0x4000000L); case 91: return jjStartNfaWithStates_3(0, 111, 2); case 93: return jjStopAtPos(0, 112); case 97: return jjMoveStringLiteralDfa1_3(0x40000000000000L); case 102: return jjMoveStringLiteralDfa1_3(0x80000L); case 105: return jjMoveStringLiteralDfa1_3(0x20000000000000L); case 116: return jjMoveStringLiteralDfa1_3(0x100000L); case 117: return jjMoveStringLiteralDfa1_3(0x80000000000000L); case 123: return jjStopAtPos(0, 115); case 125: return jjStopAtPos(0, 116); default : return jjMoveNfa_3(1, 0); } } private final int jjMoveStringLiteralDfa1_3(long active1) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_3(0, 0L, active1); return 1; } switch(curChar) { case 42: if ((active1 & 0x2000000000L) != 0L) return jjStopAtPos(1, 101); break; case 46: if ((active1 & 0x1000000L) != 0L) { jjmatchedKind = 88; jjmatchedPos = 1; } return jjMoveStringLiteralDfa2_3(active1, 0x4000000000L); case 61: if ((active1 & 0x10000000L) != 0L) return jjStopAtPos(1, 92); else if ((active1 & 0x20000000L) != 0L) return jjStopAtPos(1, 93); else if ((active1 & 0x4000000000000000L) != 0L) return jjStopAtPos(1, 126); break; case 63: if ((active1 & 0x4000000L) != 0L) return jjStopAtPos(1, 90); break; case 97: return jjMoveStringLiteralDfa2_3(active1, 0x80000L); case 110: if ((active1 & 0x20000000000000L) != 0L) return jjStartNfaWithStates_3(1, 117, 34); break; case 114: return jjMoveStringLiteralDfa2_3(active1, 0x100000L); case 115: if ((active1 & 0x40000000000000L) != 0L) return jjStartNfaWithStates_3(1, 118, 34); return jjMoveStringLiteralDfa2_3(active1, 0x80000000000000L); default : break; } return jjStartNfa_3(0, 0L, active1); } private final int jjMoveStringLiteralDfa2_3(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_3(0, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_3(1, 0L, active1); return 2; } switch(curChar) { case 46: if ((active1 & 0x4000000000L) != 0L) return jjStopAtPos(2, 102); break; case 105: return jjMoveStringLiteralDfa3_3(active1, 0x80000000000000L); case 108: return jjMoveStringLiteralDfa3_3(active1, 0x80000L); case 117: return jjMoveStringLiteralDfa3_3(active1, 0x100000L); default : break; } return jjStartNfa_3(1, 0L, active1); } private final int jjMoveStringLiteralDfa3_3(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_3(1, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_3(2, 0L, active1); return 3; } switch(curChar) { case 101: if ((active1 & 0x100000L) != 0L) return jjStartNfaWithStates_3(3, 84, 34); break; case 110: return jjMoveStringLiteralDfa4_3(active1, 0x80000000000000L); case 115: return jjMoveStringLiteralDfa4_3(active1, 0x80000L); default : break; } return jjStartNfa_3(2, 0L, active1); } private final int jjMoveStringLiteralDfa4_3(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_3(2, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_3(3, 0L, active1); return 4; } switch(curChar) { case 101: if ((active1 & 0x80000L) != 0L) return jjStartNfaWithStates_3(4, 83, 34); break; case 103: if ((active1 & 0x80000000000000L) != 0L) return jjStartNfaWithStates_3(4, 119, 34); break; default : break; } return jjStartNfa_3(3, 0L, active1); } private final int jjMoveNfa_3(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 70; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 1: if ((0x3ff000000000000L & l) != 0L) { if (kind > 85) kind = 85; jjCheckNAddStates(310, 312); } else if ((0x100002600L & l) != 0L) { if (kind > 73) kind = 73; jjCheckNAdd(0); } else if (curChar == 38) jjAddStates(313, 317); else if (curChar == 36) { if (kind > 120) kind = 120; jjCheckNAdd(34); } else if (curChar == 60) jjCheckNAdd(27); else if (curChar == 39) jjCheckNAddStates(290, 292); else if (curChar == 34) jjCheckNAddStates(293, 295); if (curChar == 38) { if (kind > 105) kind = 105; } else if (curChar == 60) { if (kind > 94) kind = 94; } if (curChar == 60) jjstateSet[jjnewStateCnt++] = 2; break; case 0: if ((0x100002600L & l) == 0L) break; if (kind > 73) kind = 73; jjCheckNAdd(0); break; case 2: if ((0xa00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 4; break; case 3: if (curChar == 45 && kind > 74) kind = 74; break; case 4: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 3; break; case 5: if (curChar == 34) jjCheckNAddStates(293, 295); break; case 6: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddStates(293, 295); break; case 8: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 9: if (curChar == 34 && kind > 81) kind = 81; break; case 11: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 12: if (curChar == 39) jjCheckNAddStates(290, 292); break; case 13: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddStates(290, 292); break; case 15: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 16: if (curChar == 39 && kind > 81) kind = 81; break; case 18: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 20: if (curChar == 34) jjCheckNAddTwoStates(21, 22); break; case 21: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddTwoStates(21, 22); break; case 22: if (curChar == 34 && kind > 82) kind = 82; break; case 23: if (curChar == 39) jjCheckNAddTwoStates(24, 25); break; case 24: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddTwoStates(24, 25); break; case 25: if (curChar == 39 && kind > 82) kind = 82; break; case 26: if (curChar == 60 && kind > 94) kind = 94; break; case 27: if (curChar == 61 && kind > 95) kind = 95; break; case 28: if (curChar == 60) jjCheckNAdd(27); break; case 29: case 67: if (curChar == 38 && kind > 105) kind = 105; break; case 33: if (curChar != 36) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 34: if ((0x3ff001000000000L & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 35: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAddStates(310, 312); break; case 36: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAdd(36); break; case 37: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddTwoStates(37, 38); break; case 38: if (curChar == 46) jjCheckNAdd(39); break; case 39: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 86) kind = 86; jjCheckNAdd(39); break; case 53: if (curChar == 38) jjAddStates(313, 317); break; case 54: if (curChar == 59 && kind > 94) kind = 94; break; case 57: if (curChar == 59) jjCheckNAdd(27); break; case 60: if (curChar == 59 && kind > 96) kind = 96; break; case 63: if (curChar == 61 && kind > 97) kind = 97; break; case 64: if (curChar == 59) jjstateSet[jjnewStateCnt++] = 63; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: if ((0x7fffffe87ffffffL & l) != 0L) { if (kind > 120) kind = 120; jjCheckNAdd(34); } else if (curChar == 92) jjAddStates(318, 321); else if (curChar == 124) jjstateSet[jjnewStateCnt++] = 31; else if (curChar == 91) jjstateSet[jjnewStateCnt++] = 2; if (curChar == 103) jjCheckNAddTwoStates(48, 69); else if (curChar == 108) jjCheckNAddTwoStates(41, 43); else if (curChar == 124) { if (kind > 106) kind = 106; } else if (curChar == 114) jjAddStates(300, 301); break; case 6: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(293, 295); break; case 7: if (curChar == 92) jjAddStates(302, 303); break; case 8: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 10: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 11; break; case 11: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(293, 295); break; case 13: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(290, 292); break; case 14: if (curChar == 92) jjAddStates(304, 305); break; case 15: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 17: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 18; break; case 18: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(290, 292); break; case 19: if (curChar == 114) jjAddStates(300, 301); break; case 21: jjAddStates(306, 307); break; case 24: jjAddStates(308, 309); break; case 30: case 31: if (curChar == 124 && kind > 106) kind = 106; break; case 32: if (curChar == 124) jjstateSet[jjnewStateCnt++] = 31; break; case 33: case 34: if ((0x7fffffe87ffffffL & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 40: if (curChar == 108) jjCheckNAddTwoStates(41, 43); break; case 41: if (curChar == 116 && kind > 94) kind = 94; break; case 42: if (curChar == 101 && kind > 95) kind = 95; break; case 43: case 46: if (curChar == 116) jjCheckNAdd(42); break; case 44: if (curChar == 92) jjAddStates(318, 321); break; case 45: if (curChar == 108) jjCheckNAdd(41); break; case 47: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 46; break; case 48: if (curChar == 116 && kind > 96) kind = 96; break; case 49: if (curChar == 103) jjCheckNAdd(48); break; case 50: if (curChar == 101 && kind > 97) kind = 97; break; case 51: case 69: if (curChar == 116) jjCheckNAdd(50); break; case 52: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 51; break; case 55: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 54; break; case 56: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 55; break; case 58: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 57; break; case 59: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 58; break; case 61: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 60; break; case 62: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 61; break; case 65: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 64; break; case 66: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 65; break; case 68: if (curChar == 103) jjCheckNAddTwoStates(48, 69); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: case 34: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 6: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(293, 295); break; case 13: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(290, 292); break; case 21: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(306, 307); break; case 24: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(308, 309); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 70 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_5(int pos, long active0, long active1) { switch (pos) { default : return -1; } } private final int jjStartNfa_5(int pos, long active0, long active1) { return jjMoveNfa_5(jjStopStringLiteralDfa_5(pos, active0, active1), pos + 1); } private final int jjStartNfaWithStates_5(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_5(state, pos + 1); } private final int jjMoveStringLiteralDfa0_5() { switch(curChar) { case 45: return jjStartNfaWithStates_5(0, 78, 3); default : return jjMoveNfa_5(1, 0); } } private final int jjMoveNfa_5(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 6; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 3: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 4; if (curChar == 45) jjstateSet[jjnewStateCnt++] = 2; break; case 1: if ((0xbfffdfffffffffffL & l) != 0L) { if (kind > 75) kind = 75; jjCheckNAdd(0); } else if (curChar == 45) jjAddStates(322, 323); break; case 0: if ((0xbfffdfffffffffffL & l) == 0L) break; kind = 75; jjCheckNAdd(0); break; case 2: if (curChar == 62) kind = 79; break; case 5: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 4; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: case 0: if ((0xffffffffdfffffffL & l) == 0L) break; kind = 75; jjCheckNAdd(0); break; case 4: if (curChar == 93) kind = 79; break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: case 0: if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) break; if (kind > 75) kind = 75; jjCheckNAdd(0); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 6 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_6(int pos, long active0, long active1) { switch (pos) { case 0: if ((active1 & 0x8000000000L) != 0L) return 32; if ((active1 & 0xe0000000180000L) != 0L) { jjmatchedKind = 120; return 29; } return -1; case 1: if ((active1 & 0x80000000180000L) != 0L) { if (jjmatchedPos != 1) { jjmatchedKind = 120; jjmatchedPos = 1; } return 29; } if ((active1 & 0x60000000000000L) != 0L) return 29; return -1; case 2: if ((active1 & 0x80000000180000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 2; return 29; } return -1; case 3: if ((active1 & 0x100000L) != 0L) return 29; if ((active1 & 0x80000000080000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 3; return 29; } return -1; default : return -1; } } private final int jjStartNfa_6(int pos, long active0, long active1) { return jjMoveNfa_6(jjStopStringLiteralDfa_6(pos, active0, active1), pos + 1); } private final int jjStartNfaWithStates_6(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_6(state, pos + 1); } private final int jjMoveStringLiteralDfa0_6() { switch(curChar) { case 33: jjmatchedKind = 107; return jjMoveStringLiteralDfa1_6(0x20000000L); case 37: return jjStopAtPos(0, 104); case 40: return jjStopAtPos(0, 113); case 41: return jjStopAtPos(0, 114); case 42: jjmatchedKind = 100; return jjMoveStringLiteralDfa1_6(0x2000000000L); case 43: return jjStopAtPos(0, 98); case 44: return jjStopAtPos(0, 108); case 45: return jjStopAtPos(0, 99); case 46: jjmatchedKind = 87; return jjMoveStringLiteralDfa1_6(0x4001000000L); case 47: return jjStartNfaWithStates_6(0, 103, 32); case 58: return jjStopAtPos(0, 110); case 59: return jjStopAtPos(0, 109); case 61: jjmatchedKind = 91; return jjMoveStringLiteralDfa1_6(0x10000000L); case 62: return jjStopAtPos(0, 123); case 63: jjmatchedKind = 89; return jjMoveStringLiteralDfa1_6(0x4000000L); case 91: return jjStopAtPos(0, 111); case 93: return jjStopAtPos(0, 112); case 97: return jjMoveStringLiteralDfa1_6(0x40000000000000L); case 102: return jjMoveStringLiteralDfa1_6(0x80000L); case 105: return jjMoveStringLiteralDfa1_6(0x20000000000000L); case 116: return jjMoveStringLiteralDfa1_6(0x100000L); case 117: return jjMoveStringLiteralDfa1_6(0x80000000000000L); case 123: return jjStopAtPos(0, 115); case 125: return jjStopAtPos(0, 116); default : return jjMoveNfa_6(0, 0); } } private final int jjMoveStringLiteralDfa1_6(long active1) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_6(0, 0L, active1); return 1; } switch(curChar) { case 42: if ((active1 & 0x2000000000L) != 0L) return jjStopAtPos(1, 101); break; case 46: if ((active1 & 0x1000000L) != 0L) { jjmatchedKind = 88; jjmatchedPos = 1; } return jjMoveStringLiteralDfa2_6(active1, 0x4000000000L); case 61: if ((active1 & 0x10000000L) != 0L) return jjStopAtPos(1, 92); else if ((active1 & 0x20000000L) != 0L) return jjStopAtPos(1, 93); break; case 63: if ((active1 & 0x4000000L) != 0L) return jjStopAtPos(1, 90); break; case 97: return jjMoveStringLiteralDfa2_6(active1, 0x80000L); case 110: if ((active1 & 0x20000000000000L) != 0L) return jjStartNfaWithStates_6(1, 117, 29); break; case 114: return jjMoveStringLiteralDfa2_6(active1, 0x100000L); case 115: if ((active1 & 0x40000000000000L) != 0L) return jjStartNfaWithStates_6(1, 118, 29); return jjMoveStringLiteralDfa2_6(active1, 0x80000000000000L); default : break; } return jjStartNfa_6(0, 0L, active1); } private final int jjMoveStringLiteralDfa2_6(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_6(0, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_6(1, 0L, active1); return 2; } switch(curChar) { case 46: if ((active1 & 0x4000000000L) != 0L) return jjStopAtPos(2, 102); break; case 105: return jjMoveStringLiteralDfa3_6(active1, 0x80000000000000L); case 108: return jjMoveStringLiteralDfa3_6(active1, 0x80000L); case 117: return jjMoveStringLiteralDfa3_6(active1, 0x100000L); default : break; } return jjStartNfa_6(1, 0L, active1); } private final int jjMoveStringLiteralDfa3_6(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_6(1, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_6(2, 0L, active1); return 3; } switch(curChar) { case 101: if ((active1 & 0x100000L) != 0L) return jjStartNfaWithStates_6(3, 84, 29); break; case 110: return jjMoveStringLiteralDfa4_6(active1, 0x80000000000000L); case 115: return jjMoveStringLiteralDfa4_6(active1, 0x80000L); default : break; } return jjStartNfa_6(2, 0L, active1); } private final int jjMoveStringLiteralDfa4_6(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_6(2, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_6(3, 0L, active1); return 4; } switch(curChar) { case 101: if ((active1 & 0x80000L) != 0L) return jjStartNfaWithStates_6(4, 83, 29); break; case 103: if ((active1 & 0x80000000000000L) != 0L) return jjStartNfaWithStates_6(4, 119, 29); break; default : break; } return jjStartNfa_6(3, 0L, active1); } private final int jjMoveNfa_6(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 69; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 32: if (curChar == 62 && kind > 124) kind = 124; break; case 0: if ((0x3ff000000000000L & l) != 0L) { if (kind > 85) kind = 85; jjCheckNAddStates(324, 326); } else if ((0x100002600L & l) != 0L) { if (kind > 127) kind = 127; jjCheckNAdd(30); } else if (curChar == 38) jjAddStates(327, 331); else if (curChar == 47) jjAddStates(332, 333); else if (curChar == 36) { if (kind > 120) kind = 120; jjCheckNAdd(29); } else if (curChar == 60) jjCheckNAdd(22); else if (curChar == 39) jjCheckNAddStates(334, 336); else if (curChar == 34) jjCheckNAddStates(337, 339); if (curChar == 38) { if (kind > 105) kind = 105; } else if (curChar == 60) { if (kind > 94) kind = 94; } break; case 1: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddStates(337, 339); break; case 3: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(337, 339); break; case 4: if (curChar == 34 && kind > 81) kind = 81; break; case 6: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(337, 339); break; case 7: if (curChar == 39) jjCheckNAddStates(334, 336); break; case 8: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddStates(334, 336); break; case 10: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(334, 336); break; case 11: if (curChar == 39 && kind > 81) kind = 81; break; case 13: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(334, 336); break; case 15: if (curChar == 34) jjCheckNAddTwoStates(16, 17); break; case 16: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddTwoStates(16, 17); break; case 17: if (curChar == 34 && kind > 82) kind = 82; break; case 18: if (curChar == 39) jjCheckNAddTwoStates(19, 20); break; case 19: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddTwoStates(19, 20); break; case 20: if (curChar == 39 && kind > 82) kind = 82; break; case 21: if (curChar == 60 && kind > 94) kind = 94; break; case 22: if (curChar == 61 && kind > 95) kind = 95; break; case 23: if (curChar == 60) jjCheckNAdd(22); break; case 24: case 66: if (curChar == 38 && kind > 105) kind = 105; break; case 28: if (curChar != 36) break; if (kind > 120) kind = 120; jjCheckNAdd(29); break; case 29: if ((0x3ff001000000000L & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(29); break; case 30: if ((0x100002600L & l) == 0L) break; if (kind > 127) kind = 127; jjCheckNAdd(30); break; case 31: if (curChar == 47) jjAddStates(332, 333); break; case 34: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAddStates(324, 326); break; case 35: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAdd(35); break; case 36: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddTwoStates(36, 37); break; case 37: if (curChar == 46) jjCheckNAdd(38); break; case 38: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 86) kind = 86; jjCheckNAdd(38); break; case 52: if (curChar == 38) jjAddStates(327, 331); break; case 53: if (curChar == 59 && kind > 94) kind = 94; break; case 56: if (curChar == 59) jjCheckNAdd(22); break; case 59: if (curChar == 59 && kind > 96) kind = 96; break; case 62: if (curChar == 61 && kind > 97) kind = 97; break; case 63: if (curChar == 59) jjstateSet[jjnewStateCnt++] = 62; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 32: if (curChar == 93 && kind > 124) kind = 124; break; case 0: if ((0x7fffffe87ffffffL & l) != 0L) { if (kind > 120) kind = 120; jjCheckNAdd(29); } else if (curChar == 92) jjAddStates(340, 343); else if (curChar == 124) jjstateSet[jjnewStateCnt++] = 26; if (curChar == 103) jjCheckNAddTwoStates(47, 68); else if (curChar == 108) jjCheckNAddTwoStates(40, 42); else if (curChar == 124) { if (kind > 106) kind = 106; } else if (curChar == 114) jjAddStates(344, 345); break; case 1: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(337, 339); break; case 2: if (curChar == 92) jjAddStates(322, 323); break; case 3: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(337, 339); break; case 5: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 6; break; case 6: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(337, 339); break; case 8: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(334, 336); break; case 9: if (curChar == 92) jjAddStates(0, 1); break; case 10: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(334, 336); break; case 12: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 13; break; case 13: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(334, 336); break; case 14: if (curChar == 114) jjAddStates(344, 345); break; case 16: jjAddStates(346, 347); break; case 19: jjAddStates(348, 349); break; case 25: case 26: if (curChar == 124 && kind > 106) kind = 106; break; case 27: if (curChar == 124) jjstateSet[jjnewStateCnt++] = 26; break; case 28: case 29: if ((0x7fffffe87ffffffL & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(29); break; case 39: if (curChar == 108) jjCheckNAddTwoStates(40, 42); break; case 40: if (curChar == 116 && kind > 94) kind = 94; break; case 41: if (curChar == 101 && kind > 95) kind = 95; break; case 42: case 45: if (curChar == 116) jjCheckNAdd(41); break; case 43: if (curChar == 92) jjAddStates(340, 343); break; case 44: if (curChar == 108) jjCheckNAdd(40); break; case 46: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 45; break; case 47: if (curChar == 116 && kind > 96) kind = 96; break; case 48: if (curChar == 103) jjCheckNAdd(47); break; case 49: if (curChar == 101 && kind > 97) kind = 97; break; case 50: case 68: if (curChar == 116) jjCheckNAdd(49); break; case 51: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 50; break; case 54: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 53; break; case 55: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 54; break; case 57: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 56; break; case 58: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 57; break; case 60: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 59; break; case 61: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 60; break; case 64: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 63; break; case 65: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 64; break; case 67: if (curChar == 103) jjCheckNAddTwoStates(47, 68); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 0: case 29: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 120) kind = 120; jjCheckNAdd(29); break; case 1: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(337, 339); break; case 8: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(334, 336); break; case 16: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(346, 347); break; case 19: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(348, 349); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 69 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } private final int jjStopStringLiteralDfa_4(int pos, long active0, long active1) { switch (pos) { case 0: if ((active1 & 0x800000000000L) != 0L) return 2; if ((active1 & 0x80020000000L) != 0L) return 36; if ((active1 & 0xe0000000180000L) != 0L) { jjmatchedKind = 120; return 34; } if ((active1 & 0x8000000000L) != 0L) return 38; return -1; case 1: if ((active1 & 0x60000000000000L) != 0L) return 34; if ((active1 & 0x80000000180000L) != 0L) { if (jjmatchedPos != 1) { jjmatchedKind = 120; jjmatchedPos = 1; } return 34; } return -1; case 2: if ((active1 & 0x80000000180000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 2; return 34; } return -1; case 3: if ((active1 & 0x100000L) != 0L) return 34; if ((active1 & 0x80000000080000L) != 0L) { jjmatchedKind = 120; jjmatchedPos = 3; return 34; } return -1; default : return -1; } } private final int jjStartNfa_4(int pos, long active0, long active1) { return jjMoveNfa_4(jjStopStringLiteralDfa_4(pos, active0, active1), pos + 1); } private final int jjStartNfaWithStates_4(int pos, int kind, int state) { jjmatchedKind = kind; jjmatchedPos = pos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return pos + 1; } return jjMoveNfa_4(state, pos + 1); } private final int jjMoveStringLiteralDfa0_4() { switch(curChar) { case 33: jjmatchedKind = 107; return jjMoveStringLiteralDfa1_4(0x20000000L); case 37: return jjStopAtPos(0, 104); case 40: return jjStopAtPos(0, 113); case 41: return jjStopAtPos(0, 114); case 42: jjmatchedKind = 100; return jjMoveStringLiteralDfa1_4(0x2000000000L); case 43: return jjStopAtPos(0, 98); case 44: return jjStopAtPos(0, 108); case 45: return jjStopAtPos(0, 99); case 46: jjmatchedKind = 87; return jjMoveStringLiteralDfa1_4(0x4001000000L); case 47: return jjStartNfaWithStates_4(0, 103, 38); case 58: return jjStopAtPos(0, 110); case 59: return jjStopAtPos(0, 109); case 61: jjmatchedKind = 91; return jjMoveStringLiteralDfa1_4(0x10000000L); case 62: return jjStopAtPos(0, 123); case 63: jjmatchedKind = 89; return jjMoveStringLiteralDfa1_4(0x4000000L); case 91: return jjStartNfaWithStates_4(0, 111, 2); case 93: return jjStopAtPos(0, 112); case 97: return jjMoveStringLiteralDfa1_4(0x40000000000000L); case 102: return jjMoveStringLiteralDfa1_4(0x80000L); case 105: return jjMoveStringLiteralDfa1_4(0x20000000000000L); case 116: return jjMoveStringLiteralDfa1_4(0x100000L); case 117: return jjMoveStringLiteralDfa1_4(0x80000000000000L); case 123: return jjStopAtPos(0, 115); case 125: return jjStopAtPos(0, 116); default : return jjMoveNfa_4(1, 0); } } private final int jjMoveStringLiteralDfa1_4(long active1) { try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_4(0, 0L, active1); return 1; } switch(curChar) { case 42: if ((active1 & 0x2000000000L) != 0L) return jjStopAtPos(1, 101); break; case 46: if ((active1 & 0x1000000L) != 0L) { jjmatchedKind = 88; jjmatchedPos = 1; } return jjMoveStringLiteralDfa2_4(active1, 0x4000000000L); case 61: if ((active1 & 0x10000000L) != 0L) return jjStopAtPos(1, 92); else if ((active1 & 0x20000000L) != 0L) return jjStopAtPos(1, 93); break; case 63: if ((active1 & 0x4000000L) != 0L) return jjStopAtPos(1, 90); break; case 97: return jjMoveStringLiteralDfa2_4(active1, 0x80000L); case 110: if ((active1 & 0x20000000000000L) != 0L) return jjStartNfaWithStates_4(1, 117, 34); break; case 114: return jjMoveStringLiteralDfa2_4(active1, 0x100000L); case 115: if ((active1 & 0x40000000000000L) != 0L) return jjStartNfaWithStates_4(1, 118, 34); return jjMoveStringLiteralDfa2_4(active1, 0x80000000000000L); default : break; } return jjStartNfa_4(0, 0L, active1); } private final int jjMoveStringLiteralDfa2_4(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_4(0, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_4(1, 0L, active1); return 2; } switch(curChar) { case 46: if ((active1 & 0x4000000000L) != 0L) return jjStopAtPos(2, 102); break; case 105: return jjMoveStringLiteralDfa3_4(active1, 0x80000000000000L); case 108: return jjMoveStringLiteralDfa3_4(active1, 0x80000L); case 117: return jjMoveStringLiteralDfa3_4(active1, 0x100000L); default : break; } return jjStartNfa_4(1, 0L, active1); } private final int jjMoveStringLiteralDfa3_4(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_4(1, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_4(2, 0L, active1); return 3; } switch(curChar) { case 101: if ((active1 & 0x100000L) != 0L) return jjStartNfaWithStates_4(3, 84, 34); break; case 110: return jjMoveStringLiteralDfa4_4(active1, 0x80000000000000L); case 115: return jjMoveStringLiteralDfa4_4(active1, 0x80000L); default : break; } return jjStartNfa_4(2, 0L, active1); } private final int jjMoveStringLiteralDfa4_4(long old1, long active1) { if (((active1 &= old1)) == 0L) return jjStartNfa_4(2, 0L, old1); try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { jjStopStringLiteralDfa_4(3, 0L, active1); return 4; } switch(curChar) { case 101: if ((active1 & 0x80000L) != 0L) return jjStartNfaWithStates_4(4, 83, 34); break; case 103: if ((active1 & 0x80000000000000L) != 0L) return jjStartNfaWithStates_4(4, 119, 34); break; default : break; } return jjStartNfa_4(3, 0L, active1); } private final int jjMoveNfa_4(int startState, int curPos) { int[] nextStates; int startsAt = 0; jjnewStateCnt = 75; int i = 1; jjstateSet[0] = startState; int j, kind = 0x7fffffff; for (;;) { if (++jjround == 0x7fffffff) ReInitRounds(); if (curChar < 64) { long l = 1L << curChar; MatchLoop: do { switch(jjstateSet[--i]) { case 1: if ((0x3ff000000000000L & l) != 0L) { if (kind > 85) kind = 85; jjCheckNAddStates(350, 352); } else if ((0x100002600L & l) != 0L) { if (kind > 73) kind = 73; jjCheckNAdd(0); } else if (curChar == 38) jjAddStates(353, 357); else if (curChar == 47) jjAddStates(358, 359); else if (curChar == 33) jjCheckNAdd(36); else if (curChar == 36) { if (kind > 120) kind = 120; jjCheckNAdd(34); } else if (curChar == 60) jjCheckNAdd(27); else if (curChar == 39) jjCheckNAddStates(290, 292); else if (curChar == 34) jjCheckNAddStates(293, 295); if (curChar == 38) { if (kind > 105) kind = 105; } else if (curChar == 60) { if (kind > 94) kind = 94; } if (curChar == 60) jjstateSet[jjnewStateCnt++] = 2; break; case 38: if (curChar == 62 && kind > 124) kind = 124; break; case 0: if ((0x100002600L & l) == 0L) break; if (kind > 73) kind = 73; jjCheckNAdd(0); break; case 2: if ((0xa00000000L & l) != 0L) jjstateSet[jjnewStateCnt++] = 4; break; case 3: if (curChar == 45 && kind > 74) kind = 74; break; case 4: if (curChar == 45) jjstateSet[jjnewStateCnt++] = 3; break; case 5: if (curChar == 34) jjCheckNAddStates(293, 295); break; case 6: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddStates(293, 295); break; case 8: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 9: if (curChar == 34 && kind > 81) kind = 81; break; case 11: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 12: if (curChar == 39) jjCheckNAddStates(290, 292); break; case 13: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddStates(290, 292); break; case 15: if ((0x9400000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 16: if (curChar == 39 && kind > 81) kind = 81; break; case 18: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 20: if (curChar == 34) jjCheckNAddTwoStates(21, 22); break; case 21: if ((0xfffffffbffffffffL & l) != 0L) jjCheckNAddTwoStates(21, 22); break; case 22: if (curChar == 34 && kind > 82) kind = 82; break; case 23: if (curChar == 39) jjCheckNAddTwoStates(24, 25); break; case 24: if ((0xffffff7fffffffffL & l) != 0L) jjCheckNAddTwoStates(24, 25); break; case 25: if (curChar == 39 && kind > 82) kind = 82; break; case 26: if (curChar == 60 && kind > 94) kind = 94; break; case 27: if (curChar == 61 && kind > 95) kind = 95; break; case 28: if (curChar == 60) jjCheckNAdd(27); break; case 29: case 72: if (curChar == 38 && kind > 105) kind = 105; break; case 33: if (curChar != 36) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 34: if ((0x3ff001000000000L & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 35: if (curChar == 33) jjCheckNAdd(36); break; case 36: if ((0x100002600L & l) == 0L) break; if (kind > 128) kind = 128; jjCheckNAdd(36); break; case 37: if (curChar == 47) jjAddStates(358, 359); break; case 40: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAddStates(350, 352); break; case 41: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 85) kind = 85; jjCheckNAdd(41); break; case 42: if ((0x3ff000000000000L & l) != 0L) jjCheckNAddTwoStates(42, 43); break; case 43: if (curChar == 46) jjCheckNAdd(44); break; case 44: if ((0x3ff000000000000L & l) == 0L) break; if (kind > 86) kind = 86; jjCheckNAdd(44); break; case 58: if (curChar == 38) jjAddStates(353, 357); break; case 59: if (curChar == 59 && kind > 94) kind = 94; break; case 62: if (curChar == 59) jjCheckNAdd(27); break; case 65: if (curChar == 59 && kind > 96) kind = 96; break; case 68: if (curChar == 61 && kind > 97) kind = 97; break; case 69: if (curChar == 59) jjstateSet[jjnewStateCnt++] = 68; break; default : break; } } while(i != startsAt); } else if (curChar < 128) { long l = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: if ((0x7fffffe87ffffffL & l) != 0L) { if (kind > 120) kind = 120; jjCheckNAdd(34); } else if (curChar == 92) jjAddStates(360, 363); else if (curChar == 124) jjstateSet[jjnewStateCnt++] = 31; else if (curChar == 91) jjstateSet[jjnewStateCnt++] = 2; if (curChar == 103) jjCheckNAddTwoStates(53, 74); else if (curChar == 108) jjCheckNAddTwoStates(46, 48); else if (curChar == 124) { if (kind > 106) kind = 106; } else if (curChar == 114) jjAddStates(300, 301); break; case 38: if (curChar == 93 && kind > 124) kind = 124; break; case 6: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(293, 295); break; case 7: if (curChar == 92) jjAddStates(302, 303); break; case 8: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(293, 295); break; case 10: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 11; break; case 11: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(293, 295); break; case 13: if ((0xffffffffefffffffL & l) != 0L) jjCheckNAddStates(290, 292); break; case 14: if (curChar == 92) jjAddStates(304, 305); break; case 15: if ((0x81450c610000000L & l) != 0L) jjCheckNAddStates(290, 292); break; case 17: if (curChar == 120) jjstateSet[jjnewStateCnt++] = 18; break; case 18: if ((0x7e0000007eL & l) != 0L) jjCheckNAddStates(290, 292); break; case 19: if (curChar == 114) jjAddStates(300, 301); break; case 21: jjAddStates(306, 307); break; case 24: jjAddStates(308, 309); break; case 30: case 31: if (curChar == 124 && kind > 106) kind = 106; break; case 32: if (curChar == 124) jjstateSet[jjnewStateCnt++] = 31; break; case 33: case 34: if ((0x7fffffe87ffffffL & l) == 0L) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 45: if (curChar == 108) jjCheckNAddTwoStates(46, 48); break; case 46: if (curChar == 116 && kind > 94) kind = 94; break; case 47: if (curChar == 101 && kind > 95) kind = 95; break; case 48: case 51: if (curChar == 116) jjCheckNAdd(47); break; case 49: if (curChar == 92) jjAddStates(360, 363); break; case 50: if (curChar == 108) jjCheckNAdd(46); break; case 52: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 51; break; case 53: if (curChar == 116 && kind > 96) kind = 96; break; case 54: if (curChar == 103) jjCheckNAdd(53); break; case 55: if (curChar == 101 && kind > 97) kind = 97; break; case 56: case 74: if (curChar == 116) jjCheckNAdd(55); break; case 57: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 56; break; case 60: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 59; break; case 61: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 60; break; case 63: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 62; break; case 64: if (curChar == 108) jjstateSet[jjnewStateCnt++] = 63; break; case 66: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 65; break; case 67: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 66; break; case 70: if (curChar == 116) jjstateSet[jjnewStateCnt++] = 69; break; case 71: if (curChar == 103) jjstateSet[jjnewStateCnt++] = 70; break; case 73: if (curChar == 103) jjCheckNAddTwoStates(53, 74); break; default : break; } } while(i != startsAt); } else { int hiByte = (int)(curChar >> 8); int i1 = hiByte >> 6; long l1 = 1L << (hiByte & 077); int i2 = (curChar & 0xff) >> 6; long l2 = 1L << (curChar & 077); MatchLoop: do { switch(jjstateSet[--i]) { case 1: case 34: if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) break; if (kind > 120) kind = 120; jjCheckNAdd(34); break; case 6: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(293, 295); break; case 13: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(290, 292); break; case 21: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(306, 307); break; case 24: if (jjCanMove_0(hiByte, i1, i2, l1, l2)) jjAddStates(308, 309); break; default : break; } } while(i != startsAt); } if (kind != 0x7fffffff) { jjmatchedKind = kind; jjmatchedPos = curPos; kind = 0x7fffffff; } ++curPos; if ((i = jjnewStateCnt) == (startsAt = 75 - (jjnewStateCnt = startsAt))) return curPos; try { curChar = input_stream.readChar(); } catch(java.io.IOException e) { return curPos; } } } static final int[] jjnextStates = { 10, 12, 4, 5, 3, 4, 5, 557, 566, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 336, 337, 345, 346, 357, 358, 369, 370, 381, 382, 391, 392, 402, 403, 413, 414, 426, 427, 436, 437, 449, 450, 463, 464, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 501, 502, 503, 515, 516, 521, 527, 528, 530, 12, 21, 24, 31, 36, 44, 51, 56, 63, 70, 76, 84, 91, 100, 106, 116, 122, 127, 134, 139, 147, 157, 166, 175, 182, 190, 199, 206, 214, 215, 223, 228, 233, 242, 251, 258, 268, 276, 287, 294, 304, 5, 6, 14, 15, 149, 150, 159, 160, 168, 169, 177, 178, 179, 184, 185, 186, 192, 193, 194, 201, 202, 203, 208, 209, 210, 216, 217, 218, 220, 221, 222, 225, 226, 227, 230, 231, 232, 235, 236, 244, 245, 246, 260, 261, 262, 278, 279, 280, 296, 297, 332, 333, 339, 340, 348, 349, 360, 361, 372, 373, 384, 385, 394, 395, 405, 406, 416, 417, 429, 430, 439, 440, 452, 453, 466, 467, 493, 494, 505, 506, 560, 561, 564, 565, 561, 563, 564, 565, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 545, 502, 546, 516, 549, 552, 528, 553, 523, 524, 559, 564, 565, 39, 40, 41, 59, 62, 65, 69, 70, 36, 37, 13, 14, 16, 6, 7, 9, 48, 50, 52, 55, 20, 23, 8, 10, 15, 17, 21, 22, 24, 25, 36, 37, 38, 56, 59, 62, 66, 67, 45, 47, 49, 52, 3, 5, 35, 36, 37, 55, 58, 61, 65, 66, 32, 33, 8, 9, 11, 1, 2, 4, 44, 46, 48, 51, 15, 18, 16, 17, 19, 20, 41, 42, 43, 61, 64, 67, 71, 72, 38, 39, 50, 52, 54, 57, }; private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) { switch(hiByte) { case 0: return ((jjbitVec2[i2] & l2) != 0L); default : if ((jjbitVec0[i1] & l1) != 0L) return true; return false; } } private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) { switch(hiByte) { case 0: return ((jjbitVec4[i2] & l2) != 0L); case 48: return ((jjbitVec5[i2] & l2) != 0L); case 49: return ((jjbitVec6[i2] & l2) != 0L); case 51: return ((jjbitVec7[i2] & l2) != 0L); case 61: return ((jjbitVec8[i2] & l2) != 0L); default : if ((jjbitVec3[i1] & l1) != 0L) return true; return false; } } public static final String[] jjstrLiteralImages = { "", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "\44\173", "\43\173", null, null, null, null, null, null, null, null, null, null, "\146\141\154\163\145", "\164\162\165\145", null, null, "\56", "\56\56", "\77", "\77\77", "\75", "\75\75", "\41\75", null, null, null, null, "\53", "\55", "\52", "\52\52", "\56\56\56", "\57", "\45", null, null, "\41", "\54", "\73", "\72", "\133", "\135", "\50", "\51", "\173", "\175", "\151\156", "\141\163", "\165\163\151\156\147", null, null, null, "\76", null, "\76", "\76\75", null, null, null, null, null, null, }; public static final String[] lexStateNames = { "DEFAULT", "NODIRECTIVE", "FM_EXPRESSION", "IN_PAREN", "NAMED_PARAMETER_EXPRESSION", "EXPRESSION_COMMENT", "NO_SPACE_EXPRESSION", "NO_PARSE", }; public static final int[] jjnewLexState = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 2, -1, -1, -1, -1, }; static final long[] jjtoToken = { 0xffffffffffffffc1L, 0xf9fffffffffe01ffL, 0x1fL, }; static final long[] jjtoSkip = { 0x0L, 0xfe00L, 0x0L, }; protected SimpleCharStream input_stream; private final int[] jjrounds = new int[567]; private final int[] jjstateSet = new int[1134]; StringBuffer image; int jjimageLen; int lengthOfMatch; protected char curChar; public FMParserTokenManager(SimpleCharStream stream) { if (SimpleCharStream.staticFlag) throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); input_stream = stream; } public FMParserTokenManager(SimpleCharStream stream, int lexState) { this(stream); SwitchTo(lexState); } public void ReInit(SimpleCharStream stream) { jjmatchedPos = jjnewStateCnt = 0; curLexState = defaultLexState; input_stream = stream; ReInitRounds(); } private final void ReInitRounds() { int i; jjround = 0x80000001; for (i = 567; i-- > 0;) jjrounds[i] = 0x80000000; } public void ReInit(SimpleCharStream stream, int lexState) { ReInit(stream); SwitchTo(lexState); } public void SwitchTo(int lexState) { if (lexState >= 8 || lexState < 0) throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); else curLexState = lexState; } protected Token jjFillToken() { Token t = Token.newToken(jjmatchedKind); t.kind = jjmatchedKind; String im = jjstrLiteralImages[jjmatchedKind]; t.image = (im == null) ? input_stream.GetImage() : im; t.beginLine = input_stream.getBeginLine(); t.beginColumn = input_stream.getBeginColumn(); t.endLine = input_stream.getEndLine(); t.endColumn = input_stream.getEndColumn(); return t; } int curLexState = 0; int defaultLexState = 0; int jjnewStateCnt; int jjround; int jjmatchedPos; int jjmatchedKind; public Token getNextToken() { int kind; Token specialToken = null; Token matchedToken; int curPos = 0; EOFLoop : for (;;) { try { curChar = input_stream.BeginToken(); } catch(java.io.IOException e) { jjmatchedKind = 0; matchedToken = jjFillToken(); return matchedToken; } image = null; jjimageLen = 0; switch(curLexState) { case 0: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_0(); break; case 1: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_1(); break; case 2: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_2(); break; case 3: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_3(); break; case 4: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_4(); break; case 5: try { input_stream.backup(0); while ((curChar < 64 && (0x4000000000000000L & (1L << curChar)) != 0L) || (curChar >> 6) == 1 && (0x20000000L & (1L << (curChar & 077))) != 0L) curChar = input_stream.BeginToken(); } catch (java.io.IOException e1) { continue EOFLoop; } jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_5(); break; case 6: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_6(); break; case 7: jjmatchedKind = 0x7fffffff; jjmatchedPos = 0; curPos = jjMoveStringLiteralDfa0_7(); break; } if (jjmatchedKind != 0x7fffffff) { if (jjmatchedPos + 1 < curPos) input_stream.backup(curPos - jjmatchedPos - 1); if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) { matchedToken = jjFillToken(); TokenLexicalActions(matchedToken); if (jjnewLexState[jjmatchedKind] != -1) curLexState = jjnewLexState[jjmatchedKind]; return matchedToken; } else { SkipLexicalActions(null); if (jjnewLexState[jjmatchedKind] != -1) curLexState = jjnewLexState[jjmatchedKind]; continue EOFLoop; } } int error_line = input_stream.getEndLine(); int error_column = input_stream.getEndColumn(); String error_after = null; boolean EOFSeen = false; try { input_stream.readChar(); input_stream.backup(1); } catch (java.io.IOException e1) { EOFSeen = true; error_after = curPos <= 1 ? "" : input_stream.GetImage(); if (curChar == '\n' || curChar == '\r') { error_line++; error_column = 0; } else error_column++; } if (!EOFSeen) { input_stream.backup(1); error_after = curPos <= 1 ? "" : input_stream.GetImage(); } throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); } } void SkipLexicalActions(Token matchedToken) { switch(jjmatchedKind) { case 79 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); if (parenthesisNesting >0) SwitchTo(IN_PAREN); else if (inInvocation) SwitchTo(NAMED_PARAMETER_EXPRESSION); else SwitchTo(FM_EXPRESSION); break; default : break; } } void TokenLexicalActions(Token matchedToken) { switch(jjmatchedKind) { case 6 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 7 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 8 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 9 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 10 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 11 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 12 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 13 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 14 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 15 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 16 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 17 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 18 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 19 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 20 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 21 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 22 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 23 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 24 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 25 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 26 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 27 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 28 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, NO_PARSE); noparseTag="comment"; break; case 29 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); noparseTag = "-->"; strictSyntaxCheck(matchedToken, NO_PARSE); break; case 30 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, NO_PARSE); noparseTag="noparse"; break; case 31 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 32 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 33 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 34 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 35 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 36 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 37 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 38 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 39 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 40 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 41 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 42 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 43 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 44 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 45 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 46 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 47 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 48 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 49 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 50 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 51 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 52 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 53 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 54 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 55 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 56 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 57 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 58 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 59 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, FM_EXPRESSION); break; case 60 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 61 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 62 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); strictSyntaxCheck(matchedToken, DEFAULT); break; case 63 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); unifiedCall(matchedToken); break; case 64 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); unifiedCallEnd(matchedToken); break; case 65 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); ftlHeader(matchedToken); break; case 66 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); ftlHeader(matchedToken); break; case 67 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); if (!directiveSyntaxEstablished && incompatibleChanges < 2003019) { matchedToken.kind = PRINTABLE_CHARS; } else { char firstChar = matchedToken.image.charAt(0); if (!directiveSyntaxEstablished && autodetectTagSyntax) { altDirectiveSyntax = (firstChar == '['); directiveSyntaxEstablished = true; } if (firstChar == '<' && altDirectiveSyntax) { matchedToken.kind = PRINTABLE_CHARS; } else if (firstChar == '[' && !altDirectiveSyntax) { matchedToken.kind = PRINTABLE_CHARS; } else if (strictEscapeSyntax) { String s = matchedToken.image; int index = s.indexOf('#'); s = s.substring(index); String msg = "Unknown directive: " + s + " on line: " + matchedToken.beginLine + ", column: " + matchedToken.beginColumn +1 + ", in template: " + templateName; throw new TokenMgrError(msg, TokenMgrError.LEXICAL_ERROR); } } break; case 111 : if (image == null) image = new StringBuffer(jjstrLiteralImages[111]); else image.append(jjstrLiteralImages[111]); ++bracketNesting; break; case 112 : if (image == null) image = new StringBuffer(jjstrLiteralImages[112]); else image.append(jjstrLiteralImages[112]); closeBracket(matchedToken); break; case 113 : if (image == null) image = new StringBuffer(jjstrLiteralImages[113]); else image.append(jjstrLiteralImages[113]); ++parenthesisNesting; if (parenthesisNesting == 1) SwitchTo(IN_PAREN); break; case 114 : if (image == null) image = new StringBuffer(jjstrLiteralImages[114]); else image.append(jjstrLiteralImages[114]); --parenthesisNesting; if (parenthesisNesting == 0) { if (inInvocation) SwitchTo(NAMED_PARAMETER_EXPRESSION); else SwitchTo(FM_EXPRESSION); } break; case 115 : if (image == null) image = new StringBuffer(jjstrLiteralImages[115]); else image.append(jjstrLiteralImages[115]); ++hashLiteralNesting; break; case 116 : if (image == null) image = new StringBuffer(jjstrLiteralImages[116]); else image.append(jjstrLiteralImages[116]); if (hashLiteralNesting == 0) SwitchTo(DEFAULT); else --hashLiteralNesting; break; case 123 : if (image == null) image = new StringBuffer(jjstrLiteralImages[123]); else image.append(jjstrLiteralImages[123]); if (inFTLHeader) eatNewline(); inFTLHeader = false; if (altDirectiveSyntax) { matchedToken.kind = NATURAL_GT; } else { SwitchTo(DEFAULT); } break; case 124 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); if (inFTLHeader) eatNewline(); inFTLHeader = false; SwitchTo(DEFAULT); break; case 129 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); if (noparseTag.equals("-->")) { boolean squareBracket = matchedToken.image.endsWith("]"); if ((altDirectiveSyntax && squareBracket) || (!altDirectiveSyntax && !squareBracket)) SwitchTo(DEFAULT); } break; case 130 : if (image == null) image = new StringBuffer(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); else image.append(new String(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)))); StringTokenizer st = new StringTokenizer(image.toString(), " \t\n\r<>[]/#", false); if (st.nextToken().equals(noparseTag)) { SwitchTo(DEFAULT); } break; default : break; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ReturnInstruction.java0000644000175000017500000000750311723544471026071 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; /** * Represents a <return> instruction to jump out of a macro. * @author Jonathan Revusky */ public final class ReturnInstruction extends TemplateElement { private Expression exp; ReturnInstruction(Expression exp) { this.exp = exp; } void accept(Environment env) throws TemplateException { if (exp != null) { env.setLastReturnValue(exp.getAsTemplateModel(env)); } if (nextSibling() != null) { // We need to jump out using an exception. throw Return.INSTANCE; } if (!(getParent() instanceof Macro || getParent().getParent() instanceof Macro)) { // Here also, we need to jump out using an exception. throw Return.INSTANCE; } } public String getCanonicalForm() { String expString = exp == null ? "" : " " + exp.getCanonicalForm(); return "<#return" + expString + "/>"; } public String getDescription() { return "return" + " [" + getStartLocation() + "]"; } public static class Return extends RuntimeException { static final Return INSTANCE = new Return(); private Return() { } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NotExpression.java0000644000175000017500000000624611723544471025173 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; final class NotExpression extends BooleanExpression { private final Expression target; NotExpression(Expression target) { this.target = target; } boolean isTrue(Environment env) throws TemplateException { return (!target.isTrue(env)); } public String getCanonicalForm() { return "!" + target.getCanonicalForm(); } boolean isLiteral() { return target.isLiteral(); } Expression _deepClone(String name, Expression subst) { return new NotExpression(target.deepClone(name, subst)); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FMParser.jj0000644000175000017500000023344611723544470023517 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ options { STATIC=false; UNICODE_INPUT=true; LEXER_CLASS="FMParserTokenManager"; CONSTANTS_CLASS="FMParserConstants"; // DEBUG_TOKEN_MANAGER=true; // DEBUG_PARSER=true; } PARSER_BEGIN(FMParser) package freemarker.core; import freemarker.template.*; import freemarker.template.utility.StringUtil; import freemarker.template.utility.DeepUnwrap; import java.io.*; import java.util.*; /** * This class is generated by JavaCC from a grammar file. */ public class FMParser { // Necessary for adding macros and setting location info. Template template; private String templateName; // variables that keep track of whether we are in a loop or a switch. private int loopNesting, switchNesting; private boolean inMacro, inFunction, stripWhitespace, stripText; private LinkedList escapes = new LinkedList(); private int contentNesting; // for stripText /** * Create an FM expression parser using a string. */ static public FMParser createExpressionParser(String s) { SimpleCharStream scs = new SimpleCharStream(new StringReader(s), 1, 1, s.length()); FMParserTokenManager token_source = new FMParserTokenManager(scs); token_source.SwitchTo(FMParserConstants.FM_EXPRESSION); return new FMParser(token_source); } /** * Constructs a new parser object. * @param template The template associated with this parser. * @param reader The character stream to use as input * @param strictEscapeSyntax Whether FreeMarker directives must start with a # */ public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace) { this(reader); this.template = template; token_source.strictEscapeSyntax = strictEscapeSyntax; this.templateName = template != null ? template.getName() : ""; token_source.templateName = templateName; this.stripWhitespace = stripWhitespace; } public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax) { this(template, reader, strictEscapeSyntax, stripWhitespace, tagSyntax, Configuration.PARSED_DEFAULT_INCOMPATIBLE_ENHANCEMENTS); } public FMParser(Template template, Reader reader, boolean strictEscapeSyntax, boolean stripWhitespace, int tagSyntax, int incompatibleChanges) { this(template, reader, strictEscapeSyntax, stripWhitespace); switch (tagSyntax) { case Configuration.AUTO_DETECT_TAG_SYNTAX : token_source.autodetectTagSyntax = true; break; case Configuration.ANGLE_BRACKET_TAG_SYNTAX : token_source.altDirectiveSyntax = false; break; case Configuration.SQUARE_BRACKET_TAG_SYNTAX : token_source.altDirectiveSyntax = true; break; default : throw new IllegalArgumentException("Illegal argument for tagSyntax"); } token_source.incompatibleChanges = incompatibleChanges; } public FMParser(String template) { this(null, new StringReader(template), true, true); } private String getErrorStart(Token t) { return "Error in template: " + template.getName() + "\non line " + t.beginLine + ", column " + t.beginColumn; } /** * Throw an exception if the expression passed in is a String * Literal */ private void notStringLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof StringLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound string literal: " + exp + "\nExpecting: " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a Number * Literal */ private void notNumberLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof NumberLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound number literal: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a boolean * Literal */ private void notBooleanLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof BooleanLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a Hash * Literal */ private void notHashLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof HashLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound hash literal: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a List * Literal */ private void notListLiteral(Expression exp, String expected) throws ParseException { if (exp instanceof ListLiteral) { String msg = "Error " + exp.getStartLocation() + "\nFound list literal: " + exp.getCanonicalForm() + "\nExpecting " + expected; throw new ParseException(msg, exp); } } /** * Throw an exception if the expression passed in is a literal * other than of the numerical type */ private void numberLiteralOnly(Expression exp) throws ParseException { notStringLiteral(exp, "number"); notListLiteral(exp, "number"); notHashLiteral(exp, "number"); notBooleanLiteral(exp, "number"); } /** * Throw an exception if the expression passed in is * not a string. */ private void stringLiteralOnly(Expression exp) throws ParseException { notNumberLiteral(exp, "number"); notListLiteral(exp, "number"); notHashLiteral(exp, "number"); notBooleanLiteral(exp, "number"); } /** * Throw an exception if the expression passed in is a literal * other than of the boolean type */ private void booleanLiteralOnly(Expression exp) throws ParseException { notStringLiteral(exp, "boolean (true/false)"); notListLiteral(exp, "boolean (true/false)"); notHashLiteral(exp, "boolean (true/false)"); notNumberLiteral(exp, "boolean (true/false)"); } private Expression escapedExpression(Expression exp) { if(!escapes.isEmpty()) { return ((EscapeBlock)escapes.getFirst()).doEscape(exp); } return exp; } private boolean getBoolean(Expression exp) throws ParseException { TemplateModel tm = null; try { tm = exp.getAsTemplateModel(null); } catch (Exception e) { throw new ParseException(e.getMessage() + "\nCould not evaluate expression: " + exp.getCanonicalForm() + exp.getStartLocation(), exp); } if (tm instanceof TemplateBooleanModel) { try { return ((TemplateBooleanModel) tm).getAsBoolean(); } catch (TemplateModelException tme) { } } if (tm instanceof TemplateScalarModel) { try { return StringUtil.getYesNo(((TemplateScalarModel) tm).getAsString()); } catch (Exception e) { throw new ParseException(e.getMessage() + "\nExpecting yes/no, found: " + exp.getCanonicalForm() + exp.getStartLocation(), exp); } } throw new ParseException("Expecting boolean (yes/no) parameter" + exp.getStartLocation(), exp); } } PARSER_END(FMParser) /** * The lexer portion defines 5 lexical states: * DEFAULT, FM_EXPRESSION, IN_PAREN, NO_PARSE, and EXPRESSION_COMMENT. * The DEFAULT state is when you are parsing * text but are not inside a FreeMarker expression. * FM_EXPRESSION is the state you are in * when the parser wants a FreeMarker expression. * IN_PAREN is almost identical really. The difference * is that you are in this state when you are within * FreeMarker expression and also within (...). * This is a necessary subtlety because the * ">" and ">=" symbols can only be used * within parentheses because otherwise, it would * be ambiguous with the end of a directive. * So, for example, you enter the FM_EXPRESSION state * right after a ${ and leave it after the matching }. * Or, you enter the FM_EXPRESSION state right after * an "" * that ends the if directive, * you go back to DEFAULT lexical state. * If, within the FM_EXPRESSION state, you enter a * parenthetical expression, you enter the IN_PAREN * state. * Note that whitespace is ignored in the * FM_EXPRESSION and IN_PAREN states * but is passed through to the parser as PCDATA in the DEFAULT state. * NO_PARSE and EXPRESSION_COMMENT are extremely simple * lexical states. NO_PARSE is when you are in a comment * block and EXPRESSION_COMMENT is when you are in a comment * that is within an FTL expression. */ TOKEN_MGR_DECLS : { /** The noparseTag is set when we enter a block of text that the parser more or less ignores. These are and . This variable tells us what the closing tag should be, and when we hit that, we resume parsing. Note that with this scheme, and tags cannot nest recursively, but it is not clear how important that is. */ String noparseTag; /** Keeps track of how deeply nested we have the hash literals. This is necessary since we need to be able to distinguish the } used to close a hash literal and the one used to close a ${ */ private int hashLiteralNesting; private int parenthesisNesting; private int bracketNesting; private boolean inFTLHeader; boolean strictEscapeSyntax, onlyTextOutput, altDirectiveSyntax, autodetectTagSyntax, directiveSyntaxEstablished, inInvocation; int incompatibleChanges; String templateName; // This method checks if we are in a strict mode where all // FreeMarker directives must start with <#. It also handled // tag syntax detection. If you update this logic, take a look // at the UNKNOWN_DIRECTIVE token too. private void strictSyntaxCheck(Token tok, int newLexState) { if (onlyTextOutput) { tok.kind = PRINTABLE_CHARS; return; } char firstChar = tok.image.charAt(0); if (autodetectTagSyntax && !directiveSyntaxEstablished) { altDirectiveSyntax = (firstChar == '['); } if ((firstChar == '[' && !altDirectiveSyntax) || (firstChar == '<' && altDirectiveSyntax)) { tok.kind = PRINTABLE_CHARS; return; } if (!strictEscapeSyntax) { SwitchTo(newLexState); return; } if (!altDirectiveSyntax) { if (!tok.image.startsWith("<#") && !tok.image.startsWith("0) { --bracketNesting; } else { tok.kind=DIRECTIVE_END; if (inFTLHeader) { eatNewline(); inFTLHeader = false; } SwitchTo(DEFAULT); } } private void eatNewline() { int charsRead = 0; try { while (true) { char c = input_stream.readChar(); ++charsRead; if (!Character.isWhitespace(c)) { input_stream.backup(charsRead); return; } else if (c=='\r') { char next = input_stream.readChar(); ++charsRead; if (next != '\n') { input_stream.backup(1); } return; } else if (c=='\n') { return; } } } catch (IOException ioe) { input_stream.backup(charsRead); } } private void ftlHeader(Token matchedToken) { if (!directiveSyntaxEstablished) { altDirectiveSyntax = matchedToken.image.charAt(0) == '['; directiveSyntaxEstablished = true; autodetectTagSyntax = false; } String img = matchedToken.image; char firstChar = img.charAt(0); char lastChar = img.charAt(img.length() -1); if ((firstChar == '[' && !altDirectiveSyntax) || (firstChar == '<' && altDirectiveSyntax)) { matchedToken.kind = PRINTABLE_CHARS; } if (matchedToken.kind != PRINTABLE_CHARS) { if (lastChar != '>' && lastChar != ']') { SwitchTo(FM_EXPRESSION); inFTLHeader = true; } else { eatNewline(); } } } } TOKEN: { <#BLANK : [" ", "\t", "\n", "\r"]> | <#START_TAG : "<" | "<#" | "[#"> | <#END_TAG : " | <#CLOSE_TAG1 : ()* (">" | "]")> | <#CLOSE_TAG2 : ()* ("/")? (">" | "]")> | "attempt" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "recover" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "if" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "elseif" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "list" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "foreach" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "switch" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "case" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "assign" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "global" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "local" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | <_INCLUDE : "include" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "import" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "function" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "macro" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "transform" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "visit" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "stop" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "return" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "call" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "setting" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "compress" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "comment" > {strictSyntaxCheck(matchedToken, NO_PARSE); noparseTag="comment";} | {noparseTag = "-->"; strictSyntaxCheck(matchedToken, NO_PARSE); } | "noparse" > {strictSyntaxCheck(matchedToken, NO_PARSE); noparseTag="noparse";} | "if" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "list" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "recover" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "attempt" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "foreach" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "local" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "global" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "assign" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "function" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "macro" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "compress" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "transform" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "switch" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "else" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "break" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "return" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "stop" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "flush" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "t" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "lt" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "rt" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "nt" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "default" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "nested" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "nested" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "recurse" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "recurse" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "fallback" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "escape" > {strictSyntaxCheck(matchedToken, FM_EXPRESSION);} | "escape" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "noescape" > {strictSyntaxCheck(matchedToken, DEFAULT);} | "noescape" > {strictSyntaxCheck(matchedToken, DEFAULT);} | {unifiedCall(matchedToken);} | ) (".")*)? > {unifiedCallEnd(matchedToken);} | > {ftlHeader(matchedToken);} | " | "]")> {ftlHeader(matchedToken);} | { if (!directiveSyntaxEstablished && incompatibleChanges < 2003019) { matchedToken.kind = PRINTABLE_CHARS; } else { char firstChar = matchedToken.image.charAt(0); if (!directiveSyntaxEstablished && autodetectTagSyntax) { altDirectiveSyntax = (firstChar == '['); directiveSyntaxEstablished = true; } if (firstChar == '<' && altDirectiveSyntax) { matchedToken.kind = PRINTABLE_CHARS; } else if (firstChar == '[' && !altDirectiveSyntax) { matchedToken.kind = PRINTABLE_CHARS; } else if (strictEscapeSyntax) { String s = matchedToken.image; int index = s.indexOf('#'); s = s.substring(index); String msg = "Unknown directive: " + s + " on line: " + matchedToken.beginLine + ", column: " + matchedToken.beginColumn +1 + ", in template: " + templateName; throw new TokenMgrError(msg, TokenMgrError.LEXICAL_ERROR); } } } } TOKEN : { | | // to handle a lone dollar sign or "<" or "# or <@ with whitespace after" | : FM_EXPRESSION | : FM_EXPRESSION } SKIP : { < ( " " | "\t" | "\n" | "\r" )+ > | < ["<", "["] ["#", "!"] "--"> : EXPRESSION_COMMENT } SKIP: { < (~["-", ">", "]"])+ > | < ">"> | < "]"> | < "-"> | < "-->" | "--]"> {if (parenthesisNesting >0) SwitchTo(IN_PAREN); else if (inInvocation) SwitchTo(NAMED_PARAMETER_EXPRESSION); else SwitchTo(FM_EXPRESSION);} } TOKEN : { <#ESCAPED_CHAR : "\\" ( ["n","t","r","f","b","g","l","a","\\","'","\"","$","{"] | ("x" ["0"-"9","A"-"F","a"-"f"]) ) > | )* "\"") | ("'" ((~["'","\\"]) | )* "'" ) > | | | | | "." > | | | | | | | | | | | | | | | | | | | | {++bracketNesting;} | {closeBracket(matchedToken);} | { ++parenthesisNesting; if (parenthesisNesting == 1) SwitchTo(IN_PAREN); } | { --parenthesisNesting; if (parenthesisNesting == 0) { if (inInvocation) SwitchTo(NAMED_PARAMETER_EXPRESSION); else SwitchTo(FM_EXPRESSION); } } | {++hashLiteralNesting;} | { if (hashLiteralNesting == 0) SwitchTo(DEFAULT); else --hashLiteralNesting; } | < IN : "in"> | < AS : "as"> | < USING : "using"> | < ID: (|)* > | < #LETTER: [ "\u0024", "\u0040"-"\u005a", "\u005f", "\u0061"-"\u007a", "\u00c0"-"\u00d6", "\u00d8"-"\u00f6", "\u00f8"-"\u00ff", "\u0100"-"\u1fff", "\u3040"-"\u318f", "\u3300"-"\u337f", "\u3400"-"\u3d2d", "\u4e00"-"\u9fff", "\uf900"-"\ufaff" ] > | < #DIGIT: [ "\u0030"-"\u0039", "\u0660"-"\u0669", "\u06f0"-"\u06f9", "\u0966"-"\u096f", "\u09e6"-"\u09ef", "\u0a66"-"\u0a6f", "\u0ae6"-"\u0aef", "\u0b66"-"\u0b6f", "\u0be7"-"\u0bef", "\u0c66"-"\u0c6f", "\u0ce6"-"\u0cef", "\u0d66"-"\u0d6f", "\u0e50"-"\u0e59", "\u0ed0"-"\u0ed9", "\u1040"-"\u1049" ] > } TOKEN : { "> { if (inFTLHeader) eatNewline(); inFTLHeader = false; if (altDirectiveSyntax) { matchedToken.kind = NATURAL_GT; } else { SwitchTo(DEFAULT); } } | " | "/]"> {if (inFTLHeader) eatNewline(); inFTLHeader = false; SwitchTo(DEFAULT);} } TOKEN : { "> | ="> } TOKEN : { : FM_EXPRESSION } TOKEN : { : FM_EXPRESSION } TOKEN : { " | "--]"> { if (noparseTag.equals("-->")) { boolean squareBracket = matchedToken.image.endsWith("]"); if ((altDirectiveSyntax && squareBracket) || (!altDirectiveSyntax && !squareBracket)) SwitchTo(DEFAULT); } } | " | "]") > { StringTokenizer st = new StringTokenizer(image.toString(), " \t\n\r<>[]/#", false); if (st.nextToken().equals(noparseTag)) { SwitchTo(DEFAULT); } } | | } // Now the actual parsing code, starting // with the productions for FreeMarker's // expression syntax. /** * This is the same as OrExpression, since * the OR is the operator with the lowest * precedence. */ Expression Expression() : { Expression exp; } { exp=OrExpression() { return exp; } } /** * Lowest level expression, a literal, a variable, * or a possibly more complex expression bounded * by parentheses. */ Expression PrimaryExpression() : { Expression exp; } { ( exp=NumberLiteral() | exp=HashLiteral() | exp=StringLiteral(true) | exp=BooleanLiteral() | exp=ListLiteral() | exp=Identifier() | exp=Parenthesis() | exp=BuiltinVariable() ) ( LOOKAHEAD( | | | | | |) exp=AddSubExpression(exp) )* { return exp; } } Expression Parenthesis() : { Expression exp, result; Token start, end; } { start= exp=Expression() end= { result = new ParentheticalExpression(exp); result.setLocation(template, start, end); return result; } } /** * A primary expression preceded by zero or * more unary operators. (The only unary operator we * currently have is the NOT.) */ Expression UnaryExpression() : { Expression exp, result; boolean haveNot = false; Token t = null, start=null; } { ( result=UnaryPlusMinusExpression() | result=NotExpression() | result=PrimaryExpression() ) { return result; } /* ( t= { haveNot = !haveNot; if (start == null) start = t; } )* exp=PrimaryExpression() { result = exp; if (haveNot) { booleanLiteralOnly(exp); result = new NotExpression(exp); result.setLocation(template, start, exp); } return result; } */ } Expression NotExpression() : { Token t; Expression exp, result=null; ArrayList nots = new ArrayList(); } { ( t= {nots.add(t);} )+ exp=PrimaryExpression() { for (int i=0; i | t= {isMinus = true;} ) exp=PrimaryExpression() { result = new UnaryPlusMinusExpression(exp, isMinus); result.setLocation(template, t, exp); return result; } } Expression AdditiveExpression() : { Expression lhs, rhs, result; boolean plus; } { lhs=MultiplicativeExpression() {result = lhs;} ( LOOKAHEAD(|) ( ( {plus = true;} | {plus = false;} ) ) rhs=MultiplicativeExpression() { if (plus) { // plus is treated separately, since it is also // used for concatenation. result = new AddConcatExpression(lhs, rhs); } else { numberLiteralOnly(lhs); numberLiteralOnly(rhs); result = new ArithmeticExpression(lhs, rhs, ArithmeticExpression.SUBSTRACTION); } result.setLocation(template, lhs, rhs); lhs = result; } )* { return result; } } /** * A unary expression followed by zero or more * unary expressions with operators in between. */ Expression MultiplicativeExpression() : { Expression lhs, rhs, result; int operation = ArithmeticExpression.MULTIPLICATION; } { lhs=UnaryExpression() {result = lhs;} ( LOOKAHEAD(||) ( ( {operation = ArithmeticExpression.MULTIPLICATION;} | {operation = ArithmeticExpression.DIVISION;} | {operation = ArithmeticExpression.MODULUS;} ) ) rhs=UnaryExpression() { numberLiteralOnly(lhs); numberLiteralOnly(rhs); result = new ArithmeticExpression(lhs, rhs, operation); result.setLocation(template, lhs, rhs); lhs = result; } )* { return result; } } Expression EqualityExpression() : { Expression lhs, rhs, result; Token t; } { lhs=RelationalExpression() {result = lhs;} [ LOOKAHEAD(||) ( t= | t= | t= ) rhs=RelationalExpression() { notHashLiteral(lhs, "scalar"); notHashLiteral(rhs, "scalar"); notListLiteral(lhs, "scalar"); notListLiteral(rhs, "scalar"); result = new ComparisonExpression(lhs, rhs, t.image); result.setLocation(template, lhs, rhs); } ] { return result; } } Expression RelationalExpression() : { Expression lhs, rhs, result; Token t; } { lhs=RangeExpression() {result = lhs;} [ LOOKAHEAD(||||||) ( t= | t= | t= | t= | t= | t= ) rhs=RangeExpression() { notHashLiteral(lhs, "scalar"); notHashLiteral(rhs, "scalar"); notListLiteral(lhs, "scalar"); notListLiteral(rhs, "scalar"); notStringLiteral(lhs, "number"); notStringLiteral(rhs, "number"); result = new ComparisonExpression(lhs, rhs, t.image); result.setLocation(template, lhs, rhs); } ] { return result; } } Expression RangeExpression() : { Expression lhs, rhs=null, result; } { lhs=AdditiveExpression() {result = lhs;} [ LOOKAHEAD() [ LOOKAHEAD(Expression()) rhs=AdditiveExpression() ] { numberLiteralOnly(lhs); if (rhs != null) { numberLiteralOnly(rhs); } Range range = new Range(lhs, rhs); if (rhs != null) { range.setLocation(template, lhs, rhs); } else { range.setLocation(template, lhs, lhs); } result = range; } ] { return result; } } Expression AndExpression() : { Expression lhs, rhs, result; } { lhs=EqualityExpression() {result = lhs;} ( LOOKAHEAD() rhs=EqualityExpression() { booleanLiteralOnly(lhs); booleanLiteralOnly(rhs); result = new AndExpression(lhs, rhs); result.setLocation(template, lhs, rhs); lhs = result; } )* { return result; } } Expression OrExpression() : { Expression lhs, rhs, result; } { lhs=AndExpression() {result = lhs;} ( LOOKAHEAD() rhs=AndExpression() { booleanLiteralOnly(lhs); booleanLiteralOnly(rhs); result = new OrExpression(lhs, rhs); result.setLocation(template, lhs, rhs); lhs = result; } )* { return result; } } ListLiteral ListLiteral() : { ArrayList values = new ArrayList(); Token begin, end; } { begin= values=PositionalArgs() end= { ListLiteral result = new ListLiteral(values); result.setLocation(template, begin, end); return result; } } Expression NumberLiteral() : { Token op = null, t; } { ( t= | t= ) { String s = t.image; Expression result = new NumberLiteral(template.getArithmeticEngine().toNumber(s)); Token startToken = (op != null) ? op : t; result.setLocation(template, startToken, t); return result; } } Identifier Identifier() : { Token t; } { t= { Identifier id = new Identifier(t.image); id.setLocation(template, t, t); return id; } } Expression IdentifierOrStringLiteral() : { Expression exp; } { ( exp=Identifier() | exp=StringLiteral(false) ) { return exp; } } BuiltinVariable BuiltinVariable() : { Token dot, name; } { dot= name= { BuiltinVariable result = null; try { result = new BuiltinVariable(name.image); } catch (ParseException pe) { pe.lineNumber = dot.beginLine; pe.columnNumber = dot.beginColumn; throw pe; } result.setLocation(template, dot, name); return result; } } /** * Production that builds up an expression * using the dot or dynamic key name * or the args list if this is a method invocation. */ Expression AddSubExpression(Expression exp) : { Expression result = null; } { ( result=DotVariable(exp) | result=DynamicKey(exp) | result=MethodArgs(exp) | result=BuiltIn(exp) | result=DefaultTo(exp) | result=Exists(exp) ) { return result; } } Expression DefaultTo(Expression exp) : { Expression rhs = null; Token t; } { ( t= | ( t= [ LOOKAHEAD(Expression()) rhs=Expression() ] ) ) { DefaultToExpression result = new DefaultToExpression(exp, rhs); if (rhs ==null) { result.setLocation(template, exp, t); } else { result.setLocation(template, exp, rhs); } return result; } } Expression Exists(Expression exp) : { Token t; } { t= { ExistsExpression result = new ExistsExpression(exp); result.setLocation(template, exp, t); return result; } } Expression BuiltIn(Expression exp) : { Token t=null; } { t= { BuiltIn result = null; try { result = BuiltIn.newBuiltIn(exp, t.image, t, templateName); } catch (ParseException pe) { pe.lineNumber = t.beginLine; pe.columnNumber = t.beginColumn; throw pe; } result.setLocation(template, exp, t); return result; } } /** * production for when a key is specified by + keyname */ Expression DotVariable(Expression exp) : { Token t; } { ( t= | t= | t= | ( t= | t= | t= | t= | t= | t= | t= | t= | t= ) { if (!Character.isLetter(t.image.charAt(0))) { String msg = getErrorStart(t) + "\n" + t.image + " is not a valid identifier."; throw new ParseException(msg, t.beginLine, t.beginColumn); } } ) { notListLiteral(exp, "hash"); notStringLiteral(exp, "hash"); notBooleanLiteral(exp, "hash"); Dot dot = new Dot(exp, t.image); dot.setLocation(template, exp, t); return dot; } } /** * production for when the key is specified * in brackets. */ Expression DynamicKey(Expression exp) : { Expression arg; Token t; } { arg=Expression() t= { notBooleanLiteral(exp, "list or hash"); notNumberLiteral(exp, "list or hash"); DynamicKeyName dkn = new DynamicKeyName(exp, arg); dkn.setLocation(template, exp, t); return dkn; } } /** * production for an arglist part of a method invocation. */ MethodCall MethodArgs(Expression exp) : { ArrayList args = new ArrayList(); Token end; } { args=PositionalArgs() end= { args.trimToSize(); MethodCall result = new MethodCall(exp, args); result.setLocation(template, exp, end); return result; } } StringLiteral StringLiteral(boolean interpolate) : { Token t; boolean raw = false; } { ( t= | t= {raw = true;} ) { String s = t.image; // Get rid of the quotes. s = s.substring(1, s.length() -1); if (raw) { s=s.substring(1); } else try { s = StringUtil.FTLStringLiteralDec(s); } catch (ParseException pe) { pe.lineNumber = t.beginLine; pe.columnNumber = t.beginColumn; throw pe; } StringLiteral result = new StringLiteral(s); result.setLocation(template, t, t); if (interpolate && !raw) { if (t.image.indexOf("${") >=0 || t.image.indexOf("#{") >=0) result.checkInterpolation(); } return result; } } Expression BooleanLiteral() : { Token t; Expression result; } { ( t= {result = new BooleanLiteral(false);} | t= {result = new BooleanLiteral(true);} ) { result.setLocation(template, t, t); return result; } } HashLiteral HashLiteral() : { Token begin, end; Expression key, value; ArrayList keys = new ArrayList(); ArrayList values = new ArrayList(); } { begin= [ key=Expression() (|) value=Expression() { stringLiteralOnly(key); keys.add(key); values.add(value); } ( key=Expression() (|) value=Expression() { stringLiteralOnly(key); keys.add(key); values.add(value); } )* ] end= { HashLiteral result = new HashLiteral(keys, values); result.setLocation(template, begin, end); return result; } } /** * A production representing the ${...} * that outputs a variable. */ DollarVariable StringOutput() : { Expression exp; Token begin, end; } { begin= exp=Expression() { notHashLiteral(exp, "scalar"); notListLiteral(exp, "scalar"); notBooleanLiteral(exp, "scalar"); } end= { DollarVariable result = new DollarVariable(exp, escapedExpression(exp)); result.setLocation(template, begin, end); return result; } } NumericalOutput NumericalOutput() : { Expression exp; Token fmt = null, begin, end; } { begin= exp=Expression() {numberLiteralOnly(exp);} [ fmt= ] end= { NumericalOutput result; if (fmt != null) { int minFrac = -1; // -1 indicates that the value has not been set int maxFrac = -1; StringTokenizer st = new StringTokenizer(fmt.image, "mM", true); char type = '-'; while (st.hasMoreTokens()) { String token = st.nextToken(); try { if (type != '-') { switch (type) { case 'm': if (minFrac != -1) throw new ParseException("invalid formatting string", fmt.beginLine, fmt.beginColumn); minFrac = Integer.parseInt(token); break; case 'M': if (maxFrac != -1) throw new ParseException("invalid formatting string", fmt.beginLine, fmt.beginColumn); maxFrac = Integer.parseInt(token); break; default: throw new ParseException(); } type = '-'; } else if (token.equals("m")) { type = 'm'; } else if (token.equals("M")) { type = 'M'; } else { throw new ParseException(); } } catch (ParseException e) { String msg = getErrorStart(fmt) + "\nInvalid format specifier " + fmt.image; throw new ParseException(msg, fmt.beginLine, fmt.beginColumn); } catch (NumberFormatException e) { String msg = getErrorStart(fmt) + "\nInvalid number in the format specifier " + fmt.image; throw new ParseException(msg, fmt.beginLine, fmt.beginColumn); } } if (maxFrac == -1) { if (minFrac == -1) { String msg = getErrorStart(fmt) + "\nInvalid format specification, at least one of m and M must be specified!"; throw new ParseException(msg, fmt.beginLine, fmt.beginColumn); } maxFrac = minFrac; } else if (minFrac == -1) { minFrac = 0; } if (minFrac > maxFrac) { String msg = getErrorStart(fmt) + "\nInvalid format specification, min cannot be greater than max!"; throw new ParseException(msg, fmt.beginLine, fmt.beginColumn); } if (minFrac > 50 || maxFrac > 50) {// sanity check String msg = getErrorStart(fmt) + "\nCannot specify more than 50 fraction digits"; throw new ParseException(msg, fmt.beginLine, fmt.beginColumn); } result = new NumericalOutput(exp, minFrac, maxFrac); } else { // if format != null result = new NumericalOutput(exp); } result.setLocation(template, begin, end); return result; } } TemplateElement If() : { Token start, end, t; Expression condition; TemplateElement block; IfBlock ifBlock; ConditionalBlock cblock; } { start= condition=Expression() block=OptionalBlock() { cblock = new ConditionalBlock(condition, block, true); cblock.setLocation(template, start, block); ifBlock = new IfBlock(cblock); } ( t= condition=Expression() LooseDirectiveEnd() block=OptionalBlock() { cblock = new ConditionalBlock(condition, block, false); cblock.setLocation(template, t, block); ifBlock.addBlock(cblock); } )* [ t= block=OptionalBlock() { cblock = new ConditionalBlock(null, block, false); cblock.setLocation(template, t, block); ifBlock.addBlock(cblock); } ] end= { ifBlock.setLocation(template, start, end); return ifBlock; } } AttemptBlock Attempt() : { Token start, end; TemplateElement block, recoveryBlock; } { start= block=OptionalBlock() recoveryBlock=Recover() ( end= | end= ) { AttemptBlock result = new AttemptBlock(block, recoveryBlock); result.setLocation(template, start, end); return result; } } RecoveryBlock Recover() : { Token start; TemplateElement block; } { start= block=OptionalBlock() { RecoveryBlock result = new RecoveryBlock(block); result.setLocation(template, start, block); return result; } } IteratorBlock List() : { Expression exp; Token index, start, end; TemplateElement block; } { start= {++loopNesting;} exp=Expression() index= block=OptionalBlock() end= { --loopNesting; IteratorBlock result = new IteratorBlock(exp, index.image, block, false); result.setLocation(template, start, end); return result; } } IteratorBlock ForEach() : { Expression exp; Token index, start, end; TemplateElement block; } { start= {++loopNesting;} index= exp=Expression() block=OptionalBlock() end= { --loopNesting; IteratorBlock result = new IteratorBlock(exp, index.image, block, true); result.setLocation(template, start, end); return result; } } VisitNode Visit() : { Token start, end; Expression targetNode, namespaces=null; } { start= targetNode=Expression() [ namespaces=Expression() ] end=LooseDirectiveEnd() { VisitNode result = new VisitNode(targetNode, namespaces); result.setLocation(template, start, end); return result; } } RecurseNode Recurse() : { Token start, end = null; Expression node=null, namespaces=null; } { ( start= | ( start= [ node=Expression() ] [ namespaces=Expression() ] end=LooseDirectiveEnd() ) ) { if (end == null) end = start; RecurseNode result = new RecurseNode(node, namespaces); result.setLocation(template, start, end); return result; } } FallbackInstruction FallBack() : { Token tok; } { tok= { if (!inMacro) { throw new ParseException(getErrorStart(tok) + "\nCannot fall back " + " outside a macro.", tok.beginLine, tok.beginColumn); } FallbackInstruction result = new FallbackInstruction(); result.setLocation(template, tok, tok); return result; } } /** * Production used to break out of a loop or a switch block. */ BreakInstruction Break() : { Token start; } { start= { if (loopNesting < 1 && switchNesting <1) { String msg = getErrorStart(start) + "\n" + start.image + " occurred outside a loop or a switch block."; throw new ParseException(msg, start.beginLine, start.beginColumn); } BreakInstruction result = new BreakInstruction(); result.setLocation(template, start, start); return result; } } /** * Production used to jump out of a macro. * The stop instruction terminates the rendering of the template. */ ReturnInstruction Return() : { Token start, end=null; Expression exp = null; } { ( start={end = start;} | start= exp=Expression() end=LooseDirectiveEnd() ) { if (inMacro) { if (exp != null) { String msg = getErrorStart(start) + "\nA macro cannot return a value"; throw new ParseException(msg, start.beginLine, start.beginColumn); } } else if (inFunction) { if (exp == null) { String msg = getErrorStart(start) + "\nA function must return a value"; throw new ParseException(msg, start.beginLine, start.beginColumn); } } else { if (exp == null) { String msg = getErrorStart(start) + "\nA return instruction can only occur inside a macro of function"; throw new ParseException(msg, start.beginLine, start.beginColumn); } } ReturnInstruction result = new ReturnInstruction(exp); result.setLocation(template, start, end); return result; } } StopInstruction Stop() : { Token start = null; Expression exp = null; } { ( start= | start= exp=Expression() LooseDirectiveEnd() ) { StopInstruction result = new StopInstruction(exp); result.setLocation(template, start, start); return result; } } TemplateElement Nested() : { Token t, end; ArrayList bodyParameters; BodyInstruction result = null; } { ( ( t= { result = new BodyInstruction(null); result.setLocation(template, t, t); } ) | ( t= bodyParameters=PositionalArgs() end=LooseDirectiveEnd() { result = new BodyInstruction(bodyParameters); result.setLocation(template, t, end); } ) ) { if (!inMacro) { throw new ParseException(getErrorStart(t) + "\nCannot use a " + t.image + " instruction outside a macro.", t.beginLine, t.beginColumn); } return result; } } TemplateElement Flush() : { Token t; } { t= { FlushInstruction result = new FlushInstruction(); result.setLocation(template, t, t); return result; } } TemplateElement Trim() : { Token t; TrimInstruction result=null; } { ( t= {result = new TrimInstruction(true, true);} | t= {result = new TrimInstruction(true, false);} | t= {result = new TrimInstruction(false, true);} | t= {result = new TrimInstruction(false, false);} ) { result.setLocation(template, t, t); return result; } } TemplateElement Assign() : { Token start, end; int scope; Token id=null; Expression nameExp, exp, nsExp=null; String varName; ArrayList assignments = new ArrayList(); Assignment ass; TemplateElement block; } { ( start= {scope = Assignment.NAMESPACE;} | start={scope = Assignment.GLOBAL;} | start= {scope = Assignment.LOCAL;} { scope = Assignment.LOCAL; if (!inMacro && !inFunction) { String msg = getErrorStart(start) + "\nLocal variable assigned outside a macro."; throw new ParseException(msg, start.beginLine, start.beginColumn); } } ) nameExp=IdentifierOrStringLiteral() { varName = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString(); } (( exp=Expression() { ass = new Assignment(varName, exp, scope); ass.setLocation(template, nameExp, exp); assignments.add(ass); } ( LOOKAHEAD([](|)) [] nameExp=IdentifierOrStringLiteral() { varName = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString(); } exp=Expression() { ass = new Assignment(varName, exp, scope); ass.setLocation(template, nameExp, exp); assignments.add(ass); } )* [ id= nsExp=Expression() {if (scope != Assignment.NAMESPACE) throw new ParseException(getErrorStart(id) + "\nCannot assign to namespace here.", id.beginLine, id.beginColumn);} ] end=LooseDirectiveEnd() { AssignmentInstruction ai = new AssignmentInstruction(scope); for (int i = 0; i< assignments.size(); i++) { ai.addAssignment((Assignment) assignments.get(i)); } ai.setNamespaceExp(nsExp); ai.setLocation(template, start, end); return ai; } ) | ( [ id= nsExp=Expression() {if (scope != Assignment.NAMESPACE) throw new ParseException(getErrorStart(id) + "\nCannot assign to namespace here.", id.beginLine, id.beginColumn);} ] block=OptionalBlock() ( end= {if (scope != Assignment.LOCAL) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags.", end.beginLine, end.beginColumn);} | end= {if (scope != Assignment.NAMESPACE) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags.", end.beginLine, end.beginColumn);} | end= {if (scope != Assignment.GLOBAL) throw new ParseException(getErrorStart(end) + "\nMismatched assignment tags", end.beginLine, end.beginColumn);} ) { BlockAssignment ba = new BlockAssignment(block, varName, scope, nsExp); ba.setLocation(template, start, end); return ba; } )) } Include Include() : { Expression nameExp; Token att, start, end; Expression exp, parseExp = null, encodingExp = null; } { start=<_INCLUDE> nameExp=Expression() [] ( att= exp=Expression() { String attString = att.image; if (attString.equalsIgnoreCase("parse")) { parseExp = exp; } else if (attString.equalsIgnoreCase("encoding")) { encodingExp = exp; } else { String msg = getErrorStart(att) + "\nexpecting parse= or encoding= to be specified."; throw new ParseException(msg, att.beginLine, att.beginColumn); } } )* end=LooseDirectiveEnd() { Include result = new Include(template, nameExp, encodingExp, parseExp); result.setLocation(template, start, end); return result; } } LibraryLoad Import() : { Token start, end, ns; Expression nameExp; } { start= nameExp=Expression() ns= end=LooseDirectiveEnd() { LibraryLoad result = new LibraryLoad(template, nameExp, ns.image); result.setLocation(template, start, end); template.addImport(result); return result; } } Macro Macro() : { Token arg, start, end; Expression nameExp; String name; ArrayList argNames = new ArrayList(); HashMap args = new HashMap(); ArrayList defNames = new ArrayList(); Expression defValue=null; TemplateElement block; boolean isFunction = false, hasDefaults=false; boolean isCatchAll = false; String catchAll = null; } { ( start= | start= {isFunction = true;} ) { if (inMacro || inFunction) { throw new ParseException(getErrorStart(start) + "\nMacros cannot be nested.", start.beginLine, start.endLine); } if (isFunction) inFunction = true; else inMacro = true; } nameExp=IdentifierOrStringLiteral() { name = (nameExp instanceof StringLiteral) ? ((StringLiteral) nameExp).getAsString() : nameExp.toString(); } [] ( arg= {defValue = null;} [ { isCatchAll = true; }] [ defValue=Expression() { defNames.add(arg.image); hasDefaults = true; } ] [] { if (catchAll != null) { throw new ParseException(getErrorStart(arg) + "\nThere may only be one \"catch-all\" parameter in a macro declaration, " + "and it must be the last parameter.", arg.beginLine, arg.endLine); } if (isCatchAll) { if (defValue != null) { throw new ParseException(getErrorStart(arg) + "\n\"Catch-all\" macro parameter may not have a default value.", arg.beginLine, arg.endLine); } catchAll = arg.image; } else { argNames.add(arg.image); if (hasDefaults && defValue == null) { throw new ParseException(getErrorStart(arg) + "\nIn a macro declaration, parameters without a default value " + "must all occur before the parameters with default values.", arg.beginLine, arg.endLine); } args.put(arg.image, defValue); } } )* [] block=OptionalBlock() ( end= { if(isFunction) throw new ParseException(getErrorStart(start) + "\nExpected function end tag here.", start.beginLine, start.endLine); } | end= { if(!isFunction) throw new ParseException(getErrorStart(start) + "\nExpected macro end tag here.", start.beginLine, start.endLine); } ) { inMacro = inFunction = false; Macro result = new Macro(name, argNames, args, block); result.setCatchAll(catchAll); result.isFunction = isFunction; result.setLocation(template, start, end); template.addMacro(result); return result; } } CompressedBlock Compress() : { TemplateElement block; Token start, end; } { start= block=OptionalBlock() end= { CompressedBlock cb = new CompressedBlock(block); cb.setLocation(template, start, end); return cb; } } TemplateElement UnifiedMacroTransform() : { Token start=null, end, t; HashMap namedArgs = null; ArrayList positionalArgs = null, bodyParameters = null; String directiveName = null; TemplateElement nestedBlock = null; Expression exp; } { start= exp=Expression() { if (exp instanceof Identifier || (exp instanceof Dot && ((Dot) exp).onlyHasIdentifiers())) { directiveName = exp.getCanonicalForm(); } } [] ( LOOKAHEAD() namedArgs = NamedArgs() | positionalArgs=PositionalArgs() ) [ {bodyParameters = new ArrayList();} [ []t= {bodyParameters.add(t.image);} ( [] []t = {bodyParameters.add(t.image);} )* ] ] ( end= | ( nestedBlock=OptionalBlock() end= { String s = end.image.substring(3); s = s.substring(0, s.length() -1).trim(); if (s.length() >0 && !s.equals(directiveName)) { String msg = getErrorStart(end); if (directiveName == null) { throw new ParseException(msg + "\nExpecting ", end.beginLine, end.beginColumn); } else { throw new ParseException(msg + "\nExpecting or ", end.beginLine, end.beginColumn); } } } ) ) { TemplateElement result = (positionalArgs != null) ? new UnifiedCall(exp, positionalArgs, nestedBlock, bodyParameters) : new UnifiedCall(exp, namedArgs, nestedBlock, bodyParameters); result.setLocation(template, start, end); return result; } } TemplateElement Call() : { Token start, end, id; HashMap namedArgs = null; ArrayList positionalArgs = null; String macroName= null; } { start= id= {macroName = id.image;} ( LOOKAHEAD() namedArgs=NamedArgs() | ( [ LOOKAHEAD() ] positionalArgs=PositionalArgs() [] ) ) end=LooseDirectiveEnd() { UnifiedCall result = null; if (positionalArgs != null) { result = new UnifiedCall(new Identifier(macroName), positionalArgs, null, null); } else { result = new UnifiedCall(new Identifier(macroName), namedArgs, null, null); } result.legacySyntax = true; result.setLocation(template, start, end); return result; } } HashMap NamedArgs() : { HashMap result = new HashMap(); Token t; Expression exp; } { ( t= { token_source.SwitchTo(token_source.NAMED_PARAMETER_EXPRESSION); token_source.inInvocation = true; } exp=Expression() { result.put(t.image, exp); } )+ { token_source.inInvocation = false; return result; } } ArrayList PositionalArgs() : { ArrayList result = new ArrayList(); Expression arg; } { [ arg=Expression() {result.add(arg);} ( [] arg=Expression() {result.add(arg);} )* ] { return result; } } Comment Comment() : { Token start, end; StringBuffer buf = new StringBuffer(); } { ( start= | start= ) end=UnparsedContent(buf) { Comment result = new Comment(buf.toString()); result.setLocation(template, start, end); return result; } } TextBlock NoParse() : { Token start, end; StringBuffer buf = new StringBuffer(); } { start= end=UnparsedContent(buf) { TextBlock result = new TextBlock(buf.toString(), true); result.setLocation(template, start, end); return result; } } TransformBlock Transform() : { Token start, end, argName; Expression exp, argExp; TemplateElement content = null; HashMap args = null; } { start= exp=Expression() [] ( argName= argExp = Expression() { if (args == null) args = new HashMap(); args.put(argName.image, argExp); } )* ( end= | (content=OptionalBlock()end=) ) { TransformBlock result = new TransformBlock(exp, args, content); result.setLocation(template, start, end); return result; } } SwitchBlock Switch() : { SwitchBlock switchBlock; Case caseIns; Expression switchExp; Token start, end; boolean defaultFound = false; } { start= switchExp=Expression() { ++switchNesting; switchBlock = new SwitchBlock(switchExp); } ( LOOKAHEAD(2) caseIns=Case() { if (caseIns.isDefault) { if (defaultFound) { String msg = getErrorStart(start) + "\nYou can only have one default case in a switch statement"; throw new ParseException(msg, start.beginLine, start.beginColumn); } defaultFound = true; } switchBlock.addCase(caseIns); } )* [] end= { --switchNesting; switchBlock.setLocation(template, start, end); return switchBlock; } } Case Case() : { Expression exp = null; TemplateElement block; boolean isDefault = false; Token start; } { [] ( start=exp=Expression() | start={isDefault = true;} ) block=OptionalBlock() { Case result = new Case(exp, block, isDefault); result.setLocation(template, start, block); return result; } } EscapeBlock Escape() : { Token variable, start, end; Expression escapeExpr; TemplateElement content; } { start= variable= escapeExpr=Expression() { EscapeBlock result = new EscapeBlock(variable.image, escapeExpr, escapedExpression(escapeExpr)); escapes.addFirst(result); } content=OptionalBlock() { result.setContent(content); escapes.removeFirst(); } end= { result.setLocation(template, start, end); return result; } } NoEscapeBlock NoEscape() : { Token start, end; TemplateElement content; } { start= { if(escapes.isEmpty()) { String msg = getErrorStart(start) + "\nnoescape with no matching escape encountered."; throw new ParseException(msg, start.beginLine, start.beginColumn); } Object escape = escapes.removeFirst(); } content=OptionalBlock() end= { escapes.addFirst(escape); NoEscapeBlock result = new NoEscapeBlock(content); result.setLocation(template, start, end); return result; } } /** * Production to terminate potentially empty elements. Either a ">" or "/>" */ Token LooseDirectiveEnd() : { Token t; } { ( t= | t= ) { return t; } } PropertySetting Setting() : { Token start, end, key; Expression value; } { start= key= value=Expression() end=LooseDirectiveEnd() { PropertySetting result = new PropertySetting(key.image, value); result.setLocation(template, start, end); return result; } } /** * A production for FreeMarker directives. */ TemplateElement FreemarkerDirective() : { TemplateElement tp; } { ( tp=If() | tp=List() | tp=ForEach() | tp=Assign() | tp=Include() | tp=Import() | tp=Macro() | tp=Compress() | tp=UnifiedMacroTransform() | tp=Call() | tp=Comment() | tp=NoParse() | tp=Transform() | tp=Switch() | tp=Setting() | tp=Break() | tp=Return() | tp=Stop() | tp=Flush() | tp=Trim() | tp=Nested() | tp=Escape() | tp=NoEscape() | tp=Visit() | tp=Recurse() | tp=FallBack() | tp=Attempt() ) { return tp; } } /** * Production for a block of raw text * i.e. text that contains no * FreeMarker directives. */ TextBlock PCData() : { StringBuffer buf = new StringBuffer(); Token t=null, start=null, prevToken = null; } { ( LOOKAHEAD(||) ( {prevToken = t;} t= | t= | t= ) { buf.append(t.image); if (start == null) start = t; {if (prevToken != null) prevToken.next = null;} } )+ { if (stripText && contentNesting == 1) return TextBlock.EMPTY_BLOCK; TextBlock result = new TextBlock(buf.toString(), false); result.setLocation(template, start, t); return result; } } /** * Production for dealing with unparsed content, * i.e. what is inside a comment or noparse tag. * It returns the ending token. The content * of the tag is put in buf. */ Token UnparsedContent(StringBuffer buf) : { Token t; } { ((t= | t= | t= | t=) { buf.append(t.image); })+ { buf.setLength(buf.length() - t.image.length()); return t; } } TemplateElement Content() : { MixedContent nodes = new MixedContent(); TemplateElement elem, begin=null; contentNesting++; } { ( LOOKAHEAD(1) // Just tells javacc that we know what we're doing. ( elem=PCData() | elem=StringOutput() | elem=NumericalOutput() | elem=FreemarkerDirective() ) { if (begin == null) { begin = elem; } nodes.addElement(elem); } )+ { contentNesting--; nodes.setLocation(template, begin, elem); return nodes; } } /** * A production freemarker text that may contain * ${...} and #{...} but no directives. */ TemplateElement FreeMarkerText() : { MixedContent nodes = new MixedContent(); TemplateElement elem, begin = null; } { ( ( elem=PCData() | elem=StringOutput() | elem=NumericalOutput() ) { if (begin == null) { begin = elem; } nodes.addElement(elem); } )+ { nodes.setLocation(template, begin, elem); return nodes; } } /** * A production for a block of optional content. * Returns an empty Text block if there is no * content. */ TemplateElement OptionalBlock() : { TemplateElement tp = TextBlock.EMPTY_BLOCK; } { [ LOOKAHEAD(1) // has no effect but to get rid of a spurious warning. tp=Content() ] { return tp; } } void HeaderElement() : { Token key; Expression exp = null; } { [] ( | ( ( key= exp=Expression() { String ks = key.image; TemplateModel value = null; try { value = exp.getAsTemplateModel(null); } catch (Exception e) { throw new ParseException("Could not evaluate expression: " + exp.getCanonicalForm() + " " + exp.getStartLocation() + "\nUnderlying cause: " + e.getMessage(), exp); } String vs = null; if (value instanceof TemplateScalarModel) { try { vs = ((TemplateScalarModel) exp).getAsString(); } catch (TemplateModelException tme) {} } if (template != null) { if (ks.equalsIgnoreCase("encoding")) { if (vs == null) { throw new ParseException("expecting encoding string here: " + exp.getStartLocation(), exp); } String encoding = template.getEncoding(); if (encoding != null && !encoding.equals(vs)) { throw new Template.WrongEncodingException(vs); } } else if (ks.equalsIgnoreCase("STRIP_WHITESPACE")) { this.stripWhitespace = getBoolean(exp); } else if (ks.equalsIgnoreCase("STRIP_TEXT")) { this.stripText = getBoolean(exp); } else if (ks.equalsIgnoreCase("STRICT_SYNTAX")) { this.token_source.strictEscapeSyntax = getBoolean(exp); } else if (ks.equalsIgnoreCase("ns_prefixes")) { if (!(value instanceof TemplateHashModelEx)) { throw new ParseException("Expecting a hash of prefixes to namespace URI's here. " + exp.getStartLocation(), exp); } TemplateHashModelEx prefixMap = (TemplateHashModelEx) value; try { TemplateCollectionModel keys = prefixMap.keys(); for (TemplateModelIterator it = keys.iterator(); it.hasNext();) { String prefix = ((TemplateScalarModel) it.next()).getAsString(); TemplateModel valueModel = prefixMap.get(prefix); if (!(valueModel instanceof TemplateScalarModel)) { throw new ParseException("Non-string value in prefix to namespace hash. " + exp.getStartLocation(), exp); } String nsURI = ((TemplateScalarModel) valueModel).getAsString(); try { template.addPrefixNSMapping(prefix, nsURI); } catch (IllegalArgumentException iae) { throw new ParseException(iae.getMessage() + " " + exp.getStartLocation(), exp); } } } catch (TemplateModelException tme) { } } else if (ks.equalsIgnoreCase("attributes")) { if (!(value instanceof TemplateHashModelEx)) { throw new ParseException("Expecting a hash of attribute names to values here. " + exp.getStartLocation(), exp); } TemplateHashModelEx attributeMap = (TemplateHashModelEx) value; try { TemplateCollectionModel keys = attributeMap.keys(); for (TemplateModelIterator it = keys.iterator(); it.hasNext();) { String attName = ((TemplateScalarModel) it.next()).getAsString(); Object attValue = DeepUnwrap.unwrap(attributeMap.get(attName)); template.setCustomAttribute(attName, attValue); } } catch (TemplateModelException tme) { } } else { throw new ParseException("Unknown FTL header parameter: " + key.image, key.beginLine, key.beginColumn); } } } )* ) LooseDirectiveEnd() ) } Map ParamList() : { Identifier id; Expression exp; Map result = new HashMap(); } { ( id=Identifier() exp=Expression() {result.put(id.toString(), exp);} [] )+ { return result; } } /** * Root production to be used when parsing * an entire file. */ TemplateElement Root() : { TemplateElement doc; } { [ LOOKAHEAD([](|)) HeaderElement() ] doc=OptionalBlock() { doc.setParentRecursively(null); return doc.postParseCleanup(stripWhitespace); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/EvaluationUtil.java0000644000175000017500000001114511723544471025312 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.Date; import freemarker.template.*; /** * @version 1.0 * @author Attila Szegedi */ class EvaluationUtil { private EvaluationUtil() { } static String getString(TemplateScalarModel model, Expression expr, Environment env) throws TemplateException { String value = model.getAsString(); if(value == null) { if(env.isClassicCompatible()) { return ""; } else { throw new TemplateException(expr + " evaluated to null string.", env); } } return value; } static Number getNumber(Expression expr, Environment env) throws TemplateException { TemplateModel model = expr.getAsTemplateModel(env); return getNumber(model, expr, env); } static Number getNumber(TemplateModel model, Expression expr, Environment env) throws TemplateException { if(model instanceof TemplateNumberModel) { return getNumber((TemplateNumberModel)model, expr, env); } else if(model == null) { throw new InvalidReferenceException(expr + " is undefined.", env); } else { throw new NonNumericalException(expr + " is not a number, it is " + model.getClass().getName(), env); } } static Number getNumber(TemplateNumberModel model, Expression expr, Environment env) throws TemplateModelException, TemplateException { Number value = model.getAsNumber(); if(value == null) { throw new TemplateException(expr + " evaluated to null number.", env); } return value; } static Date getDate(TemplateDateModel model, Expression expr, Environment env) throws TemplateModelException, TemplateException { Date value = model.getAsDate(); if(value == null) { throw new TemplateException(expr + " evaluated to null date.", env); } return value; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/LibraryLoad.java0000644000175000017500000001323611723544470024553 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.Template; import freemarker.template.TemplateException; /** * An instruction that gets another template * and processes it within the current template. */ public final class LibraryLoad extends TemplateElement { private Expression templateName; private String namespace; private final String templatePath; /** * @param template the template that this Include is a part of. * @param templateName the name of the template to be included. * @param namespace the namespace to assign this library to */ LibraryLoad(Template template, Expression templateName, String namespace) { this.namespace = namespace; String templatePath1 = template.getName(); int lastSlash = templatePath1.lastIndexOf('/'); templatePath = lastSlash == -1 ? "" : templatePath1.substring(0, lastSlash + 1); this.templateName = templateName; } void accept(Environment env) throws TemplateException, IOException { String templateNameString = templateName.getStringValue(env); if( templateNameString == null ) { String msg = "Error " + getStartLocation() + "The expression " + templateName + " is undefined."; throw new InvalidReferenceException(msg, env); } Template importedTemplate; try { if(!env.isClassicCompatible()) { if (templateNameString.indexOf("://") >0) { ; } else if(templateNameString.length() > 0 && templateNameString.charAt(0) == '/') { int protIndex = templatePath.indexOf("://"); if (protIndex >0) { templateNameString = templatePath.substring(0, protIndex + 2) + templateNameString; } else { templateNameString = templateNameString.substring(1); } } else { templateNameString = templatePath + templateNameString; } } importedTemplate = env.getTemplateForImporting(templateNameString); } catch (ParseException pe) { String msg = "Error parsing imported template " + templateNameString; throw new TemplateException(msg, pe, env); } catch (IOException ioe) { String msg = "Error reading imported file " + templateNameString; throw new TemplateException(msg, ioe, env); } env.importLib(importedTemplate, namespace); } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#import "); buf.append(templateName); buf.append(" as "); buf.append(namespace); buf.append("/>"); return buf.toString(); } public String getDescription() { return "import " + templateName + " as " + namespace; } public String getTemplateName() { return templateName.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TemplateObject.java0000644000175000017500000002040411723544472025246 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import freemarker.template.utility.StringUtil; /** * Objects that represent instructions or expressions * in the compiled tree representation of the template * all descend from this abstract base class. */ public abstract class TemplateObject { private Template template; int beginColumn, beginLine, endColumn, endLine; final void setLocation(Template template, Token begin, Token end) throws ParseException { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } final void setLocation(Template template, Token begin, TemplateObject end) throws ParseException { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } final void setLocation(Template template, TemplateObject begin, Token end) throws ParseException { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } final void setLocation(Template template, TemplateObject begin, TemplateObject end) throws ParseException { setLocation(template, begin.beginColumn, begin.beginLine, end.endColumn, end.endLine); } public final int getBeginColumn() { return beginColumn; } public final int getBeginLine() { return beginLine; } public final int getEndColumn() { return endColumn; } public final int getEndLine() { return endLine; } void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine) throws ParseException { this.template = template; this.beginColumn = beginColumn; this.beginLine = beginLine; this.endColumn = endColumn; this.endLine = endLine; } static void assertNonNull(TemplateModel model, Expression exp, Environment env) throws InvalidReferenceException { if (model == null) { throw new InvalidReferenceException( "Expression " + exp + " is undefined " + exp.getStartLocation() + ".", env); } } static TemplateException invalidTypeException(TemplateModel model, Expression exp, Environment env, String expected) throws TemplateException { assertNonNull(model, exp, env); return new TemplateException( "Expected " + expected + ". " + exp + " evaluated instead to " + model.getClass().getName() + " " + exp.getStartLocation() + ".", env); } /** * Returns a string that indicates * where in the template source, this object is. */ public String getStartLocation() { String templateName = template != null ? template.getName() : "input"; return "on line " + beginLine + ", column " + beginColumn + " in " + templateName; } /** * Same as {@link #getStartLocation}, but quotes the template name with * {@link StringUtil#jQuoteNoXSS(String)}. If the template name is unknown, * it uses "input" as the template name without quotation * marks. */ public String getStartLocationQuoted() { String templateName = template != null ? StringUtil.jQuoteNoXSS(template.getName()) : "input"; return "on line " + beginLine + ", column " + beginColumn + " in " + templateName; } public String getEndLocation() { String templateName = template != null ? template.getName() : "input"; return "on line " + endLine + ", column " + endColumn + " in " + templateName; } /** * Same as {@link #getStartLocation}, but quotes the template name with * {@link StringUtil#jQuoteNoXSS(String)}. If the template name is unknown, * it uses "input" as the template name without quotation * marks. */ public String getEndLocationQuoted() { String templateName = template != null ? StringUtil.jQuoteNoXSS(template.getName()) : "input"; return "on line " + endLine + ", column " + endColumn + " in " + templateName; } public final String getSource() { if (template != null) { return template.getSource(beginColumn, beginLine, endColumn, endLine); } else { return getCanonicalForm(); } } public String toString() { try { return getSource(); } catch (Exception e) { // REVISIT: A bit of a hack? (JR) return getCanonicalForm(); } } /** * @return whether the point in the template file specified by the * column and line numbers is contained within this template object. */ public boolean contains(int column, int line) { if (line < beginLine || line > endLine) { return false; } if (line == beginLine) { if (column < beginColumn) { return false; } } if (line == endLine) { if (column > endColumn) { return false; } } return true; } public Template getTemplate() { return template; } TemplateObject copyLocationFrom(TemplateObject from) { template = from.template; beginColumn = from.beginColumn; beginLine = from.beginLine; endColumn = from.endColumn; endLine = from.endLine; return this; } abstract public String getCanonicalForm(); } libfreemarker-java-2.3.19.orig/src/freemarker/core/MethodCall.java0000644000175000017500000001240211723544470024355 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ /* * 22 October 1999: This class added by Holger Arendt. */ package freemarker.core; import java.util.ArrayList; import java.util.List; import java.io.Writer; import freemarker.template.*; import java.io.IOException; /** * A unary operator that calls a TemplateMethodModel. It associates with the * Identifier or Dot to its left. */ final class MethodCall extends Expression { private final Expression target; private final ListLiteral arguments; MethodCall(Expression target, ArrayList arguments) { this(target, new ListLiteral(arguments)); } private MethodCall(Expression target, ListLiteral arguments) { this.target = target; this.arguments = arguments; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel targetModel = target.getAsTemplateModel(env); if (targetModel instanceof TemplateMethodModel) { TemplateMethodModel targetMethod = (TemplateMethodModel)targetModel; List argumentStrings = targetMethod instanceof TemplateMethodModelEx ? arguments.getModelList(env) : arguments.getValueList(env); Object result = targetMethod.exec(argumentStrings); return env.getObjectWrapper().wrap(result); } else if (targetModel instanceof Macro) { Macro func = (Macro) targetModel; env.setLastReturnValue(null); if (!func.isFunction) { throw new TemplateException("A macro cannot be called in an expression.", env); } Writer prevOut = env.getOut(); try { env.setOut(Environment.NULL_WRITER); env.visit(func, null, arguments.values, null, null); } catch (IOException ioe) { throw new InternalError("This should be impossible."); } finally { env.setOut(prevOut); } return env.getLastReturnValue(); } else { throw invalidTypeException(targetModel, target, env, "method"); } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer(); buf.append(target.getCanonicalForm()); buf.append("("); String list = arguments.getCanonicalForm(); buf.append(list.substring(1, list.length() -1)); buf.append(")"); return buf.toString(); } TemplateModel getConstantValue() { return null; } boolean isLiteral() { return false; } Expression _deepClone(String name, Expression subst) { return new MethodCall(target.deepClone(name, subst), (ListLiteral)arguments.deepClone(name, subst)); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TransformBlock.java0000644000175000017500000001212111723544471025266 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.*; import java.util.*; import freemarker.template.*; /** * A template element that contains a nested block * that is transformed according to an instance of T * TemplateTransformModel */ final class TransformBlock extends TemplateElement { private Expression transformExpression; Map namedArgs; /** * Creates new TransformBlock, with a given transformation */ TransformBlock(Expression transformExpression, Map namedArgs, TemplateElement nestedBlock) { this.transformExpression = transformExpression; this.namedArgs = namedArgs; this.nestedBlock = nestedBlock; } void accept(Environment env) throws TemplateException, IOException { TemplateTransformModel ttm = env.getTransform(transformExpression); if (ttm != null) { Map args; if (namedArgs != null && !namedArgs.isEmpty()) { args = new HashMap(); for (Iterator it = namedArgs.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String key = (String) entry.getKey(); Expression valueExp = (Expression) entry.getValue(); TemplateModel value = valueExp.getAsTemplateModel(env); args.put(key, value); } } else { args = EmptyMap.instance; } env.visit(nestedBlock, ttm, args); } else { TemplateModel tm = transformExpression.getAsTemplateModel(env); throw invalidTypeException(tm, transformExpression, env, "transform"); } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#transform "); buf.append(transformExpression); if (namedArgs != null) { for (Iterator it = namedArgs.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); buf.append(' '); buf.append(entry.getKey()); buf.append('='); Expression val = (Expression) entry.getValue(); buf.append(val.getCanonicalForm()); } } buf.append(">"); if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } buf.append(""); return buf.toString(); } public String getDescription() { return "transform " + transformExpression; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ListLiteral.java0000644000175000017500000001601211723544471024573 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import freemarker.template.*; import freemarker.template.utility.Collections12; import java.io.IOException; final class ListLiteral extends Expression { final ArrayList values; ListLiteral(ArrayList values) { this.values = values; values.trimToSize(); } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { SimpleSequence list = new SimpleSequence(values.size()); for (Iterator it = values.iterator(); it.hasNext();) { Expression exp = (Expression) it.next(); TemplateModel tm = exp.getAsTemplateModel(env); assertNonNull(tm, exp, env); list.add(tm); } return list; } /** * For the benefit of method calls, return the list of arguments as a list * of values. */ List getValueList(Environment env) throws TemplateException { int size = values.size(); switch(size) { case 0: { return Collections.EMPTY_LIST; } case 1: { return Collections12.singletonList(((Expression)values.get(0)).getStringValue(env)); } default: { List result = new ArrayList(values.size()); for (ListIterator iterator = values.listIterator(); iterator.hasNext();) { Expression exp = (Expression)iterator.next(); result.add(exp.getStringValue(env)); } return result; } } } /** * For the benefit of extended method calls, return the list of arguments as a * list of template models. */ List getModelList(Environment env) throws TemplateException { int size = values.size(); switch(size) { case 0: { return Collections.EMPTY_LIST; } case 1: { return Collections12.singletonList(((Expression)values.get(0)).getAsTemplateModel(env)); } default: { List result = new ArrayList(values.size()); for (ListIterator iterator = values.listIterator(); iterator.hasNext();) { Expression exp = (Expression)iterator.next(); result.add(exp.getAsTemplateModel(env)); } return result; } } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("["); int size = values.size(); for (int i = 0; i */ public ParseException(Token currentTokenVal, int[][] expectedTokenSequencesVal, String[] tokenImageVal ) { super(""); specialConstructor = true; currentToken = currentTokenVal; expectedTokenSequences = expectedTokenSequencesVal; tokenImage = tokenImageVal; } /** * The following constructors are for use by you for whatever * purpose you can think of. Constructing the exception in this * manner makes the exception behave in the normal way - i.e., as * documented in the class "Throwable". The fields "errorToken", * "expectedTokenSequences", and "tokenImage" do not contain * relevant information. The JavaCC generated code does not use * these constructors. */ protected ParseException() { super(); specialConstructor = false; } /* public ParseException(String message) { super(message); specialConstructor = false; } */ public ParseException(String message, int lineNumber, int columnNumber) { super(message); specialConstructor = false; this.lineNumber = lineNumber; this.columnNumber = columnNumber; } public ParseException(String message, TemplateObject tobj) { super(message); specialConstructor = false; this.lineNumber = tobj.beginLine; this.columnNumber = tobj.beginColumn; } /** * This variable determines which constructor was used to create * this object and thereby affects the semantics of the * "getMessage" method (see below). */ protected boolean specialConstructor; /** * This is the last token that has been consumed successfully. If * this object has been created due to a parse error, the token * following this token will (therefore) be the first error token. */ public Token currentToken; public int columnNumber, lineNumber; /** * Each entry in this array is an array of integers. Each array * of integers represents a sequence of tokens (by their ordinal * values) that is expected at this point of the parse. */ public int[][] expectedTokenSequences; /** * This is a reference to the "tokenImage" array of the generated * parser within which the parse error occurred. This array is * defined in the generated ...Constants interface. */ public String[] tokenImage; private String templateName = "unknown template"; public void setTemplateName(String templateName) { this.templateName = templateName; } /** * This method has the standard behavior when this object has been * created using the standard constructors. Otherwise, it uses * "currentToken" and "expectedTokenSequences" to generate a parse * error message and returns it. If this object has been created * due to a parse error, and you do not catch it (it gets thrown * from the parser), then this method is called during the printing * of the final stack trace, and hence the correct error message * gets displayed. */ public String getMessage() { if (!specialConstructor) { return super.getMessage() + " in " + templateName; } String retval = customGetMessage(); if (retval != null) { return retval; } // The default JavaCC message generation stuff follows. String expected = ""; int maxSize = 0; for (int i = 0; i < expectedTokenSequences.length; i++) { if (maxSize < expectedTokenSequences[i].length) { maxSize = expectedTokenSequences[i].length; } for (int j = 0; j < expectedTokenSequences[i].length; j++) { expected += tokenImage[expectedTokenSequences[i][j]] + " "; } if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { expected += "..."; } expected += eol + " "; } retval = "Encountered \""; Token tok = currentToken.next; for (int i = 0; i < maxSize; i++) { if (i != 0) retval += " "; if (tok.kind == 0) { retval += tokenImage[0]; break; } retval += add_escapes(tok.image); tok = tok.next; } retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; retval += " in " + templateName + "." + eol; if (expectedTokenSequences.length == 1) { retval += "Was expecting:" + eol + " "; } else { retval += "Was expecting one of:" + eol + " "; } retval += expected; return retval; } public int getLineNumber() { return currentToken != null ? currentToken.next.beginLine : lineNumber; } public int getColumnNumber() { return currentToken != null ? currentToken.next.beginColumn : columnNumber; } // Custom message generation private String customGetMessage() { Token nextToken = currentToken.next; int kind = nextToken.kind; if (kind == EOF) { StringBuffer buf = new StringBuffer("Unexpected end of file reached.\n"); for (int i = 0; i 0x7e) { String s = "0000" + Integer.toString(ch, 16); retval.append("\\u" + s.substring(s.length() - 4, s.length())); } else { retval.append(ch); } continue; } } return retval.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/RegexBuiltins.java0000644000175000017500000004312311723544471025132 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import freemarker.cache.MruCacheStorage; import freemarker.log.Logger; import freemarker.template.ObjectWrapper; import freemarker.template.SimpleScalar; import freemarker.template.SimpleSequence; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateException; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.StringUtil; /** * Implementation of built-ins that (might) use regular expressions. */ // TODO: I think that the implementator has neglected that Matcher-s are // stateful and hence the result of ?matches can produce glitches if it's // accessed while iterated through. (This is a single-thread issue.) abstract class RegexBuiltins { private static final Logger logger = Logger.getLogger("freemarker.runtime"); private static volatile boolean flagWarningsEnabled = logger.isWarnEnabled(); private static final int MAX_FLAG_WARNINGS_LOGGED = 25; private static final Object flagWarningsCntSync = new Object(); private static int flagWarningsCnt; static final MruCacheStorage patternCache = new MruCacheStorage(50, 150); // Standard regular expression flags converted to long: private static final long RE_FLAG_CASE_INSENSITIVE = intFlagToLong(Pattern.CASE_INSENSITIVE); private static final long RE_FLAG_MULTILINE = intFlagToLong(Pattern.MULTILINE); private static final long RE_FLAG_COMMENTS = intFlagToLong(Pattern.COMMENTS); private static final long RE_FLAG_DOTALL = intFlagToLong(Pattern.DOTALL); // FreeMarker-specific regular expression flags (using the higher 32 bits): private static final long RE_FLAG_REGEXP = 0x100000000L; private static final long RE_FLAG_FIRST_ONLY = 0x200000000L; static private long intFlagToLong(int flag) { return flag & 0x0000FFFFL; } static Pattern getPattern(String patternString, int flags) throws TemplateModelException { PatternCacheKey patternKey = new PatternCacheKey(patternString, flags); Pattern result; synchronized (patternCache) { result = (Pattern) patternCache.get(patternKey); } if (result != null) { return result; } try { result = Pattern.compile(patternString, flags); } catch (PatternSyntaxException e) { throw new TemplateModelException(e); } synchronized (patternCache) { patternCache.put(patternKey, result); } return result; } private static class PatternCacheKey { private final String patternString; private final int flags; private final int hashCode; public PatternCacheKey(String patternString, int flags) { this.patternString = patternString; this.flags = flags; hashCode = patternString.hashCode() + 31 * flags; } public boolean equals(Object that) { if (that instanceof PatternCacheKey) { PatternCacheKey thatPCK = (PatternCacheKey) that; return thatPCK.flags == flags && thatPCK.patternString.equals(patternString); } else { return false; } } public int hashCode() { return hashCode; } } private static long parseFlagString(String flagString) { long flags = 0; for (int i = 0; i < flagString.length(); i++) { char c = flagString.charAt(i); switch (c) { case 'i': flags |= RE_FLAG_CASE_INSENSITIVE; break; case 'm': flags |= RE_FLAG_MULTILINE; break; case 'c': flags |= RE_FLAG_COMMENTS; break; case 's': flags |= RE_FLAG_DOTALL; break; case 'r': flags |= RE_FLAG_REGEXP; break; case 'f': flags |= RE_FLAG_FIRST_ONLY; break; default: if (flagWarningsEnabled) { logFlagWarning( "Unrecognized regular expression flag: " + StringUtil.jQuote(String.valueOf(c)) + "."); } } // switch } return flags; } /** * Logs flag warning for a limited number of times. This is used to prevent * log flooding. */ private static void logFlagWarning(String message) { if (!flagWarningsEnabled) return; int cnt; synchronized (flagWarningsCntSync) { cnt = flagWarningsCnt; if (cnt < MAX_FLAG_WARNINGS_LOGGED) { flagWarningsCnt++; } else { flagWarningsEnabled = false; return; } } message += " This will be an error in FreeMarker 2.4!"; if (cnt + 1 == MAX_FLAG_WARNINGS_LOGGED) { message += " [Will not log more regular expression flag problems until restart!]"; } logger.warn(message); } static class matchesBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel targetModel = target.getAsTemplateModel(env); assertNonNull(targetModel, this, env); if (!(targetModel instanceof TemplateScalarModel)) { throw invalidTypeException(targetModel, target, env, "string"); } return new MatcherBuilder((TemplateScalarModel) targetModel); } } static class groupsBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel targetModel = target.getAsTemplateModel(env); assertNonNull(targetModel, this, env); if (targetModel instanceof RegexMatchModel) { return ((RegexMatchModel) targetModel).getGroups(); } if (targetModel instanceof RegexMatchModel.Match) { return ((RegexMatchModel.Match) targetModel).subs; } throw invalidTypeException(targetModel, target, env, "a regular expression matcher"); } } static class replace_reBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new ReplaceMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } } static class split_reBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new SplitMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } } // Represents the match static class RegexMatchModel implements TemplateBooleanModel, TemplateCollectionModel, TemplateSequenceModel { final Matcher matcher; final String input; final boolean matches; TemplateSequenceModel groups; private ArrayList data; RegexMatchModel(Matcher matcher, String input) { this.matcher = matcher; this.input = input; this.matches = matcher.matches(); } public boolean getAsBoolean() { return matches; } public TemplateModel get(int i) throws TemplateModelException { if (data == null) initSequence(); return (TemplateModel) data.get(i); } public int size() throws TemplateModelException { if (data == null) initSequence(); return data.size(); } private void initSequence() throws TemplateModelException { data = new ArrayList(); TemplateModelIterator it = iterator(); while (it.hasNext()) { data.add(it.next()); } } public TemplateModel getGroups() { if (groups == null) { groups = new TemplateSequenceModel() { public int size() throws TemplateModelException { try { return matcher.groupCount() + 1; } catch (Exception e) { throw new TemplateModelException(e); } } public TemplateModel get(int i) throws TemplateModelException { try { return new SimpleScalar(matcher.group(i)); } catch (Exception e) { throw new TemplateModelException(e); } } }; } return groups; } public TemplateModelIterator iterator() { matcher.reset(); return new TemplateModelIterator() { boolean hasFindInfo = matcher.find(); public boolean hasNext() { return hasFindInfo; } public TemplateModel next() throws TemplateModelException { if (!hasNext()) throw new TemplateModelException("No more matches"); Match result = new Match(); hasFindInfo = matcher.find(); return result; } }; } class Match implements TemplateScalarModel { String match; SimpleSequence subs = new SimpleSequence(); Match() { match = input.substring(matcher.start(), matcher.end()); for (int i=0; i< matcher.groupCount() + 1; i++) { subs.add(matcher.group(i)); } } public String getAsString() { return match; } } } static class MatcherBuilder implements TemplateMethodModel { String matchString; MatcherBuilder(TemplateScalarModel match) throws TemplateModelException { this.matchString = match.getAsString(); } public Object exec(List args) throws TemplateModelException { int numArgs = args.size(); if (numArgs == 0) { throw new TemplateModelException("Expecting at least one argument"); } if (numArgs > 2) { throw new TemplateModelException("Expecting at most two argumnets"); } String patternString = (String) args.get(0); long flags = numArgs > 1 ? parseFlagString((String) args.get(1)) : 0; if ((flags & RE_FLAG_FIRST_ONLY) != 0) { logFlagWarning("?match doesn't support the \"f\" flag."); } Pattern pattern = getPattern(patternString, (int) flags); Matcher matcher = pattern.matcher(matchString); return new RegexMatchModel(matcher, matchString); } } private static void checkNonRegexpFlags(String biName, long flags) { if (!flagWarningsEnabled) return; if ((flags & RE_FLAG_MULTILINE) != 0) { logFlagWarning("?" + biName + " doesn't support the \"m\" flag " + "without the \"r\" flag."); } if ((flags & RE_FLAG_DOTALL) != 0) { logFlagWarning("?" + biName + " doesn't support the \"s\" flag " + "without the \"r\" flag."); } if ((flags & RE_FLAG_COMMENTS) != 0) { logFlagWarning("?" + biName + " doesn't support the \"c\" flag " + "without the \"r\" flag."); } } static class ReplaceMethod implements TemplateMethodModel { private String s; ReplaceMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { int numArgs = args.size(); if (numArgs < 2 || numArgs > 3) { throw new TemplateModelException( "?replace(...) needs 2 or 3 arguments."); } String arg1 = (String) args.get(0); String arg2 = (String) args.get(1); long flags = numArgs > 2 ? parseFlagString((String) args.get(2)) : 0; String result; if ((flags & RE_FLAG_REGEXP) == 0) { checkNonRegexpFlags("replace", flags); result = StringUtil.replace(s, arg1, arg2, (flags & RE_FLAG_CASE_INSENSITIVE) != 0, (flags & RE_FLAG_FIRST_ONLY) != 0); } else { Pattern pattern = getPattern(arg1, (int) flags); Matcher matcher = pattern.matcher(s); result = (flags & RE_FLAG_FIRST_ONLY) != 0 ? matcher.replaceFirst(arg2) : matcher.replaceAll(arg2); } return new SimpleScalar(result); } } static class SplitMethod implements TemplateMethodModel { private String s; SplitMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { int numArgs = args.size(); if (numArgs < 1 || numArgs >2 ) { throw new TemplateModelException( "?replace(...) needs 1 or 2 arguments."); } String splitString = (String) args.get(0); long flags = numArgs > 1 ? parseFlagString((String) args.get(1)) : 0; String[] result = null; if ((flags & RE_FLAG_REGEXP) == 0) { checkNonRegexpFlags("split", flags); result = StringUtil.split(s, splitString, (flags & RE_FLAG_CASE_INSENSITIVE) != 0); } else { Pattern pattern = getPattern(splitString, (int) flags); result = pattern.split(s); } return ObjectWrapper.DEFAULT_WRAPPER.wrap(result); } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NoEscapeBlock.java0000644000175000017500000000636411723544470025023 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.TemplateException; /** * @version $Id: NoEscapeBlock.java,v 1.1 2003/04/22 21:05:04 revusky Exp $ * @author Attila Szegedi */ class NoEscapeBlock extends TemplateElement { NoEscapeBlock(TemplateElement nestedBlock) { this.nestedBlock = nestedBlock; } void accept(Environment env) throws TemplateException, IOException { if (nestedBlock != null) { env.visit(nestedBlock); } } public String getCanonicalForm() { return "<#noescape>" + nestedBlock.getCanonicalForm() + ""; } public String getDescription() { return "noescape block"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NumericalRange.java0000644000175000017500000000737311723544470025250 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * A class that represents a Range between two integers. * inclusive of the end-points. It can be ascending or * descending. * @author Jonathan Revusky */ class NumericalRange implements TemplateSequenceModel, java.io.Serializable { private int lower, upper; private boolean descending, norhs; // if norhs is true, then we have a half-range, like n.. /** * Constructor for half-range, i.e. n.. */ public NumericalRange(int lower) { this.norhs = true; this.lower = lower; } public NumericalRange(int left, int right) { lower = Math.min(left, right); upper = Math.max(left, right); descending = (left != lower); } public TemplateModel get(int i) throws TemplateModelException { int index = descending ? (upper -i) : (lower + i); if ((norhs && index > upper) || index Jonathan Revusky */ public class InvalidReferenceException extends TemplateException { public InvalidReferenceException(Environment env) { super("invalid reference", env); } public InvalidReferenceException(String description, Environment env) { super(description, env); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NumericalBuiltins.java0000644000175000017500000002434511723544470026003 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Date; import freemarker.template.SimpleDate; import freemarker.template.SimpleNumber; import freemarker.template.SimpleScalar; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; /** * A holder for builtins that operate exclusively on TemplateSequenceModels. */ abstract class NumericalBuiltins { abstract static class NumberBuiltIn extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); return calculateResult(EvaluationUtil.getNumber(model, target, env), model); } abstract TemplateModel calculateResult(Number num, TemplateModel model) throws TemplateModelException; } static class byteBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { if (num instanceof Byte) { return model; } return new SimpleNumber(new Byte(num.byteValue())); } } static class shortBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { if (num instanceof Short) { return model; } return new SimpleNumber(new Short(num.shortValue())); } } static class intBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { if (num instanceof Integer) { return model; } return new SimpleNumber(num.intValue()); } } // Does both someNumber?long and someDate?long, thus it doesn't extend NumberBuiltIn static class longBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (!(model instanceof TemplateNumberModel) && model instanceof TemplateDateModel) { Date date = EvaluationUtil.getDate((TemplateDateModel) model, target, env); return new SimpleNumber(date.getTime()); } else { Number num = EvaluationUtil.getNumber(model, target, env); if (num instanceof Long) { return model; } return new SimpleNumber(num.longValue()); } } } static class floatBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { if (num instanceof Float) { return model; } return new SimpleNumber(num.floatValue()); } } static class doubleBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { if (num instanceof Double) { return model; } return new SimpleNumber(num.doubleValue()); } } private static final BigDecimal BIG_DECIMAL_ONE = new BigDecimal("1"); static class floorBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { return new SimpleNumber(new BigDecimal(num.doubleValue()).divide(BIG_DECIMAL_ONE, 0, BigDecimal.ROUND_FLOOR)); } } static class ceilingBI extends NumberBuiltIn { TemplateModel calculateResult(Number num, TemplateModel model) { return new SimpleNumber(new BigDecimal(num.doubleValue()).divide(BIG_DECIMAL_ONE, 0, BigDecimal.ROUND_CEILING)); } } static class roundBI extends NumberBuiltIn { private static final BigDecimal half = new BigDecimal("0.5"); TemplateModel calculateResult(Number num, TemplateModel model) { return new SimpleNumber(new BigDecimal(num.doubleValue()).add(half).divide(BIG_DECIMAL_ONE, 0, BigDecimal.ROUND_FLOOR)); } } // Doesn't extend NumberBuiltIn because "calculateResult" would need the Environment. static class cBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); Number num = EvaluationUtil.getNumber(model, target, env); if (num instanceof Integer) { // We accelerate this fairly common case return new SimpleScalar(num.toString()); } else { return new SimpleScalar(env.getCNumberFormat().format(num)); } } } private static final BigDecimal BIG_DECIMAL_LONG_MIN = BigDecimal.valueOf(Long.MIN_VALUE); private static final BigDecimal BIG_DECIMAL_LONG_MAX = BigDecimal.valueOf(Long.MAX_VALUE); private static final BigInteger BIG_INTEGER_LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE); private static final BigInteger BIG_INTEGER_LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE); private static final long safeToLong(Number num) throws TemplateModelException { if (num instanceof Double) { double d = Math.round(((Double) num).doubleValue()); if (d > Long.MAX_VALUE || d < Long.MIN_VALUE) { throw new TemplateModelException( "Number doesn't fit into a 64 bit signed integer (long): " + d); } else { return (long) d; } } else if (num instanceof Float) { float f = Math.round(((Float) num).floatValue()); if (f > Long.MAX_VALUE || f < Long.MIN_VALUE) { throw new TemplateModelException( "Number doesn't fit into a 64 bit signed integer (long): " + f); } else { return (long) f; } } else if (num instanceof BigDecimal) { BigDecimal bd = ((BigDecimal) num).setScale(0, BigDecimal.ROUND_HALF_UP); if (bd.compareTo(BIG_DECIMAL_LONG_MAX) > 0 || bd.compareTo(BIG_DECIMAL_LONG_MIN) < 0) { throw new TemplateModelException( "Number doesn't fit into a 64 bit signed integer (long): " + bd); } else { return bd.longValue(); } } else if (num instanceof BigInteger) { BigInteger bi = (BigInteger) num; if (bi.compareTo(BIG_INTEGER_LONG_MAX) > 0 || bi.compareTo(BIG_INTEGER_LONG_MIN) < 0) { throw new TemplateModelException( "Number doesn't fit into a 64 bit signed integer (long): " + bi); } else { return bi.longValue(); } } else if (num instanceof Long || num instanceof Integer || num instanceof Byte || num instanceof Short) { // Should add Atomic* types in 2.4... return num.longValue(); } else { throw new TemplateModelException( "Unsupported number type: " + num.getClass()); } } static class number_to_dateBI extends NumberBuiltIn { private final int dateType; number_to_dateBI(int dateType) { this.dateType = dateType; } TemplateModel calculateResult(Number num, TemplateModel model) throws TemplateModelException { return new SimpleDate(new Date(safeToLong(num)), dateType); } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NonNumericalException.java0000644000175000017500000000615011723544471026616 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; /** * A subclass of TemplateException that * indicates that the internals expected an expression * to evaluate to a numerical value and it didn't. * @author Jonathan Revusky */ public class NonNumericalException extends TemplateException { public NonNumericalException(Environment env) { super("expecting numerical value here", env); } public NonNumericalException(String description, Environment env) { super(description, env); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NonStringException.java0000644000175000017500000000611211723544471026143 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; /** * A subclass of TemplateException that * indicates that the internals expected an expression * to evaluate to a string or numeric value and it didn't. * @author Attila Szegedi */ public class NonStringException extends TemplateException { public NonStringException(Environment env) { super("expecting string or numerical value here", env); } public NonStringException(String description, Environment env) { super(description, env); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BooleanExpression.java0000644000175000017500000000550511723544470026006 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; abstract class BooleanExpression extends Expression { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return isTrue(env) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/AndExpression.java0000644000175000017500000000654511723544470025136 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; final class AndExpression extends BooleanExpression { private final Expression left; private final Expression right; AndExpression(Expression left, Expression right) { this.left = left; this.right = right; } boolean isTrue(Environment env) throws TemplateException { return left.isTrue(env) && right.isTrue(env); } public String getCanonicalForm() { return left.getCanonicalForm() + " && " + right.getCanonicalForm(); } boolean isLiteral() { return constantValue != null || (left.isLiteral() && right.isLiteral()); } Expression _deepClone(String name, Expression subst) { return new AndExpression(left.deepClone(name, subst), right.deepClone(name, subst)); } }libfreemarker-java-2.3.19.orig/src/freemarker/core/Expression.java0000644000175000017500000001635711723544470024515 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import freemarker.ext.beans.BeanModel; /** * An abstract class for nodes in the parse tree * that represent a FreeMarker expression. */ abstract public class Expression extends TemplateObject { abstract TemplateModel _getAsTemplateModel(Environment env) throws TemplateException; abstract boolean isLiteral(); // Used to store a constant return value for this expression. Only if it // is possible, of course. TemplateModel constantValue; // Hook in here to set the constant value if possible. void setLocation(Template template, int beginColumn, int beginLine, int endColumn, int endLine) throws ParseException { super.setLocation(template, beginColumn, beginLine, endColumn, endLine); if (isLiteral()) { try { constantValue = _getAsTemplateModel(null); } catch (Exception e) { // deliberately ignore. } } } public final TemplateModel getAsTemplateModel(Environment env) throws TemplateException { return constantValue != null ? constantValue : _getAsTemplateModel(env); } String getStringValue(Environment env) throws TemplateException { return getStringValue(getAsTemplateModel(env), this, env); } static String getStringValue(TemplateModel referentModel, Expression exp, Environment env) throws TemplateException { if (referentModel instanceof TemplateNumberModel) { return env.formatNumber(EvaluationUtil.getNumber((TemplateNumberModel) referentModel, exp, env)); } if (referentModel instanceof TemplateDateModel) { TemplateDateModel dm = (TemplateDateModel) referentModel; return env.formatDate(EvaluationUtil.getDate(dm, exp, env), dm.getDateType()); } if (referentModel instanceof TemplateScalarModel) { return EvaluationUtil.getString((TemplateScalarModel) referentModel, exp, env); } if(env.isClassicCompatible()) { if (referentModel instanceof TemplateBooleanModel) { return ((TemplateBooleanModel)referentModel).getAsBoolean() ? "true" : ""; } if (referentModel == null) { return ""; } } assertNonNull(referentModel, exp, env); String msg = "Error " + exp.getStartLocation() +"\nExpecting a string, " + (env.isClassicCompatible() ? "boolean, " : "" ) + "date or number here, Expression " + exp + " is instead a " + referentModel.getClass().getName(); throw new NonStringException(msg, env); } Expression deepClone(String name, Expression subst) { Expression clone = _deepClone(name, subst); clone.copyLocationFrom(this); return clone; } abstract Expression _deepClone(String name, Expression subst); boolean isTrue(Environment env) throws TemplateException { TemplateModel referent = getAsTemplateModel(env); if (referent instanceof TemplateBooleanModel) { return ((TemplateBooleanModel) referent).getAsBoolean(); } if (env.isClassicCompatible()) { return referent != null && !isEmpty(referent); } assertNonNull(referent, this, env); String msg = "Error " + getStartLocation() + "\nExpecting a boolean (true/false) expression here" + "\nExpression " + this + " does not evaluate to true/false " + "\nit is an instance of " + referent.getClass().getName(); throw new NonBooleanException(msg, env); } static boolean isEmpty(TemplateModel model) throws TemplateModelException { if (model instanceof BeanModel) { return ((BeanModel) model).isEmpty(); } else if (model instanceof TemplateSequenceModel) { return ((TemplateSequenceModel) model).size() == 0; } else if (model instanceof TemplateScalarModel) { String s = ((TemplateScalarModel) model).getAsString(); return (s == null || s.length() == 0); } else if (model instanceof TemplateCollectionModel) { return !((TemplateCollectionModel) model).iterator().hasNext(); } else if (model instanceof TemplateHashModel) { return ((TemplateHashModel) model).isEmpty(); } else if (model instanceof TemplateNumberModel || model instanceof TemplateDateModel || model instanceof TemplateBooleanModel) { return false; } else { return true; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Configurable.java0000644000175000017500000014544511723544472024761 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.util.*; import freemarker.template.*; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.StringUtil; import freemarker.ext.beans.BeansWrapper; /** * This is a common superclass of {@link freemarker.template.Configuration}, * {@link freemarker.template.Template}, and {@link Environment} classes. * It provides settings that are common to each of them. FreeMarker * uses a three-level setting hierarchy - the return value of every setting * getter method on Configurable objects inherits its value from its parent * Configurable object, unless explicitly overridden by a call to a * corresponding setter method on the object itself. The parent of an * Environment object is a Template object, the * parent of a Template object is a Configuration * object. * * @version $Id: Configurable.java,v 1.23.2.2 2007/04/02 13:46:43 szegedia Exp $ * @author Attila Szegedi */ public class Configurable { public static final String LOCALE_KEY = "locale"; public static final String NUMBER_FORMAT_KEY = "number_format"; public static final String TIME_FORMAT_KEY = "time_format"; public static final String DATE_FORMAT_KEY = "date_format"; public static final String DATETIME_FORMAT_KEY = "datetime_format"; public static final String TIME_ZONE_KEY = "time_zone"; public static final String CLASSIC_COMPATIBLE_KEY = "classic_compatible"; public static final String TEMPLATE_EXCEPTION_HANDLER_KEY = "template_exception_handler"; public static final String ARITHMETIC_ENGINE_KEY = "arithmetic_engine"; public static final String OBJECT_WRAPPER_KEY = "object_wrapper"; public static final String BOOLEAN_FORMAT_KEY = "boolean_format"; public static final String OUTPUT_ENCODING_KEY = "output_encoding"; public static final String URL_ESCAPING_CHARSET_KEY = "url_escaping_charset"; public static final String STRICT_BEAN_MODELS = "strict_bean_models"; /** @since 2.3.17 */ public static final String AUTO_FLUSH_KEY = "auto_flush"; /** @since 2.3.17 */ public static final String NEW_BUILTIN_CLASS_RESOLVER_KEY = "new_builtin_class_resolver"; private static final char COMMA = ','; private Configurable parent; private Properties properties; private HashMap customAttributes; private Locale locale; private String numberFormat; private String timeFormat; private String dateFormat; private String dateTimeFormat; private TimeZone timeZone; private String trueFormat; private String falseFormat; private Boolean classicCompatible; private TemplateExceptionHandler templateExceptionHandler; private ArithmeticEngine arithmeticEngine; private ObjectWrapper objectWrapper; private String outputEncoding; private boolean outputEncodingSet; private String urlEscapingCharset; private boolean urlEscapingCharsetSet; private Boolean autoFlush; private TemplateClassResolver newBuiltinClassResolver; public Configurable() { parent = null; locale = Locale.getDefault(); timeZone = TimeZone.getDefault(); numberFormat = "number"; timeFormat = ""; dateFormat = ""; dateTimeFormat = ""; trueFormat = "true"; falseFormat = "false"; classicCompatible = Boolean.FALSE; templateExceptionHandler = TemplateExceptionHandler.DEBUG_HANDLER; arithmeticEngine = ArithmeticEngine.BIGDECIMAL_ENGINE; objectWrapper = ObjectWrapper.DEFAULT_WRAPPER; autoFlush = Boolean.TRUE; newBuiltinClassResolver = TemplateClassResolver.UNRESTRICTED_RESOLVER; // outputEncoding and urlEscapingCharset defaults to null, // which means "not specified" properties = new Properties(); properties.setProperty(LOCALE_KEY, locale.toString()); properties.setProperty(TIME_FORMAT_KEY, timeFormat); properties.setProperty(DATE_FORMAT_KEY, dateFormat); properties.setProperty(DATETIME_FORMAT_KEY, dateTimeFormat); properties.setProperty(TIME_ZONE_KEY, timeZone.getID()); properties.setProperty(NUMBER_FORMAT_KEY, numberFormat); properties.setProperty(CLASSIC_COMPATIBLE_KEY, classicCompatible.toString()); properties.setProperty(TEMPLATE_EXCEPTION_HANDLER_KEY, templateExceptionHandler.getClass().getName()); properties.setProperty(ARITHMETIC_ENGINE_KEY, arithmeticEngine.getClass().getName()); properties.setProperty(BOOLEAN_FORMAT_KEY, "true,false"); properties.setProperty(AUTO_FLUSH_KEY, autoFlush.toString()); properties.setProperty(NEW_BUILTIN_CLASS_RESOLVER_KEY, newBuiltinClassResolver.getClass().getName()); // as outputEncoding and urlEscapingCharset defaults to null, // they are not set customAttributes = new HashMap(); } /** * Creates a new instance. Normally you do not need to use this constructor, * as you don't use Configurable directly, but its subclasses. */ public Configurable(Configurable parent) { this.parent = parent; locale = null; numberFormat = null; trueFormat = null; falseFormat = null; classicCompatible = null; templateExceptionHandler = null; properties = new Properties(parent.properties); customAttributes = new HashMap(); } protected Object clone() throws CloneNotSupportedException { Configurable copy = (Configurable)super.clone(); copy.properties = new Properties(properties); copy.customAttributes = (HashMap)customAttributes.clone(); return copy; } /** * Returns the parent Configurable object of this object. * The parent stores the default values for this configurable. For example, * the parent of the {@link freemarker.template.Template} object is the * {@link freemarker.template.Configuration} object, so setting values not * specfied on template level are specified by the confuration object. * * @return the parent Configurable object, or null, if this is * the root Configurable object. */ public final Configurable getParent() { return parent; } /** * Reparenting support. This is used by Environment when it includes a * template - the included template becomes the parent configurable during * its evaluation. */ final void setParent(Configurable parent) { this.parent = parent; } /** * Toggles the "Classic Compatibile" mode. For a comprehensive description * of this mode, see {@link #isClassicCompatible()}. */ public void setClassicCompatible(boolean classicCompatibility) { this.classicCompatible = classicCompatibility ? Boolean.TRUE : Boolean.FALSE; properties.setProperty(CLASSIC_COMPATIBLE_KEY, classicCompatible.toString()); } /** * Returns whether the engine runs in the "Classic Compatibile" mode. * When this mode is active, the engine behavior is altered in following * way: (these resemble the behavior of the 1.7.x line of FreeMarker engine, * now named "FreeMarker Classic", hence the name). *

    *
  • handle undefined expressions gracefully. Namely when an expression * "expr" evaluates to null: *
      *
    • as argument of the <assign varname=expr> directive, * ${expr} directive, otherexpr == expr or * otherexpr != expr conditional expressions, or * hash[expr] expression, then it is treated as empty string. *
    • *
    • as argument of <list expr as item> or * <foreach item in expr>, the loop body is not executed * (as if it were a 0-length list) *
    • *
    • as argument of <if> directive, or otherwise where a * boolean expression is expected, it is treated as false *
    • *
    *
  • *
  • Non-boolean models are accepted in <if> directive, * or as operands of logical operators. "Empty" models (zero-length string, * empty sequence or hash) are evaluated as false, all others are evaluated as * true.
  • *
  • When boolean value is treated as a string (i.e. output in * ${...} directive, or concatenated with other string), true * values are converted to string "true", false values are converted to * empty string. *
  • *
  • Scalar models supplied to <list> and * <foreach> are treated as a one-element list consisting * of the passed model. *
  • *
  • Paths parameter of <include> will be interpreted as * absolute path. *
  • *
* In all other aspects, the engine is a 2.1 engine even in compatibility * mode - you don't lose any of the new functionality by enabling it. */ public boolean isClassicCompatible() { return classicCompatible != null ? classicCompatible.booleanValue() : parent.isClassicCompatible(); } /** * Sets the locale to assume when searching for template files with no * explicit requested locale. */ public void setLocale(Locale locale) { if (locale == null) throw new IllegalArgumentException("Setting \"locale\" can't be null"); this.locale = locale; properties.setProperty(LOCALE_KEY, locale.toString()); } /** * Returns the time zone to use when formatting time values. Defaults to * system time zone. */ public TimeZone getTimeZone() { return timeZone != null ? timeZone : parent.getTimeZone(); } /** * Sets the time zone to use when formatting time values. */ public void setTimeZone(TimeZone timeZone) { if (timeZone == null) throw new IllegalArgumentException("Setting \"time_zone\" can't be null"); this.timeZone = timeZone; properties.setProperty(TIME_ZONE_KEY, timeZone.getID()); } /** * Returns the assumed locale when searching for template files with no * explicit requested locale. Defaults to system locale. */ public Locale getLocale() { return locale != null ? locale : parent.getLocale(); } /** * Sets the number format used to convert numbers to strings. */ public void setNumberFormat(String numberFormat) { if (numberFormat == null) throw new IllegalArgumentException("Setting \"number_format\" can't be null"); this.numberFormat = numberFormat; properties.setProperty(NUMBER_FORMAT_KEY, numberFormat); } /** * Returns the default number format used to convert numbers to strings. * Defaults to "number" */ public String getNumberFormat() { return numberFormat != null ? numberFormat : parent.getNumberFormat(); } public void setBooleanFormat(String booleanFormat) { if (booleanFormat == null) { throw new IllegalArgumentException("Setting \"boolean_format\" can't be null"); } int comma = booleanFormat.indexOf(COMMA); if(comma == -1) { throw new IllegalArgumentException("Setting \"boolean_format\" must consist of two comma-separated values for true and false respectively"); } trueFormat = booleanFormat.substring(0, comma); falseFormat = booleanFormat.substring(comma + 1); properties.setProperty(BOOLEAN_FORMAT_KEY, booleanFormat); } public String getBooleanFormat() { if(trueFormat == null) { return parent.getBooleanFormat(); } return trueFormat + COMMA + falseFormat; } String getBooleanFormat(boolean value) { return value ? getTrueFormat() : getFalseFormat(); } private String getTrueFormat() { return trueFormat != null ? trueFormat : parent.getTrueFormat(); } private String getFalseFormat() { return falseFormat != null ? falseFormat : parent.getFalseFormat(); } /** * Sets the date format used to convert date models representing time-only * values to strings. */ public void setTimeFormat(String timeFormat) { if (timeFormat == null) throw new IllegalArgumentException("Setting \"time_format\" can't be null"); this.timeFormat = timeFormat; properties.setProperty(TIME_FORMAT_KEY, timeFormat); } /** * Returns the date format used to convert date models representing * time-only dates to strings. * Defaults to "time" */ public String getTimeFormat() { return timeFormat != null ? timeFormat : parent.getTimeFormat(); } /** * Sets the date format used to convert date models representing date-only * dates to strings. */ public void setDateFormat(String dateFormat) { if (dateFormat == null) throw new IllegalArgumentException("Setting \"date_format\" can't be null"); this.dateFormat = dateFormat; properties.setProperty(DATE_FORMAT_KEY, dateFormat); } /** * Returns the date format used to convert date models representing * date-only dates to strings. * Defaults to "date" */ public String getDateFormat() { return dateFormat != null ? dateFormat : parent.getDateFormat(); } /** * Sets the date format used to convert date models representing datetime * dates to strings. */ public void setDateTimeFormat(String dateTimeFormat) { if (dateTimeFormat == null) throw new IllegalArgumentException("Setting \"datetime_format\" can't be null"); this.dateTimeFormat = dateTimeFormat; properties.setProperty(DATETIME_FORMAT_KEY, dateTimeFormat); } /** * Returns the date format used to convert date models representing datetime * dates to strings. * Defaults to "datetime" */ public String getDateTimeFormat() { return dateTimeFormat != null ? dateTimeFormat : parent.getDateTimeFormat(); } /** * Sets the exception handler used to handle template exceptions. * * @param templateExceptionHandler the template exception handler to use for * handling {@link TemplateException}s. By default, * {@link TemplateExceptionHandler#HTML_DEBUG_HANDLER} is used. */ public void setTemplateExceptionHandler(TemplateExceptionHandler templateExceptionHandler) { if (templateExceptionHandler == null) throw new IllegalArgumentException("Setting \"template_exception_handler\" can't be null"); this.templateExceptionHandler = templateExceptionHandler; properties.setProperty(TEMPLATE_EXCEPTION_HANDLER_KEY, templateExceptionHandler.getClass().getName()); } /** * Retrieves the exception handler used to handle template exceptions. */ public TemplateExceptionHandler getTemplateExceptionHandler() { return templateExceptionHandler != null ? templateExceptionHandler : parent.getTemplateExceptionHandler(); } /** * Sets the arithmetic engine used to perform arithmetic operations. * * @param arithmeticEngine the arithmetic engine used to perform arithmetic * operations.By default, {@link ArithmeticEngine#BIGDECIMAL_ENGINE} is * used. */ public void setArithmeticEngine(ArithmeticEngine arithmeticEngine) { if (arithmeticEngine == null) throw new IllegalArgumentException("Setting \"arithmetic_engine\" can't be null"); this.arithmeticEngine = arithmeticEngine; properties.setProperty(ARITHMETIC_ENGINE_KEY, arithmeticEngine.getClass().getName()); } /** * Retrieves the arithmetic engine used to perform arithmetic operations. */ public ArithmeticEngine getArithmeticEngine() { return arithmeticEngine != null ? arithmeticEngine : parent.getArithmeticEngine(); } /** * Sets the object wrapper used to wrap objects to template models. * * @param objectWrapper the object wrapper used to wrap objects to template * models.By default, {@link ObjectWrapper#DEFAULT_WRAPPER} is used. */ public void setObjectWrapper(ObjectWrapper objectWrapper) { if (objectWrapper == null) throw new IllegalArgumentException("Setting \"object_wrapper\" can't be null"); this.objectWrapper = objectWrapper; properties.setProperty(OBJECT_WRAPPER_KEY, objectWrapper.getClass().getName()); } /** * Retrieves the object wrapper used to wrap objects to template models. */ public ObjectWrapper getObjectWrapper() { return objectWrapper != null ? objectWrapper : parent.getObjectWrapper(); } /** * Sets the output encoding. Allows null, which means that the * output encoding is not known. */ public void setOutputEncoding(String outputEncoding) { this.outputEncoding = outputEncoding; // java.util.Properties doesn't allow null value! if (outputEncoding != null) { properties.setProperty(OUTPUT_ENCODING_KEY, outputEncoding); } else { properties.remove(OUTPUT_ENCODING_KEY); } outputEncodingSet = true; } public String getOutputEncoding() { return outputEncodingSet ? outputEncoding : (parent != null ? parent.getOutputEncoding() : null); } /** * Sets the URL escaping charset. Allows null, which means that the * output encoding will be used for URL escaping. */ public void setURLEscapingCharset(String urlEscapingCharset) { this.urlEscapingCharset = urlEscapingCharset; // java.util.Properties doesn't allow null value! if (urlEscapingCharset != null) { properties.setProperty(URL_ESCAPING_CHARSET_KEY, urlEscapingCharset); } else { properties.remove(URL_ESCAPING_CHARSET_KEY); } urlEscapingCharsetSet = true; } public String getURLEscapingCharset() { return urlEscapingCharsetSet ? urlEscapingCharset : (parent != null ? parent.getURLEscapingCharset() : null); } /** * Sets the {@link TemplateClassResolver} that is used when the * new built-in is called in a template. That is, when * a template contains the "com.example.SomeClassName"?new * expression, this object will be called to resolve the * "com.example.SomeClassName" string to a class. The default * value is {@link TemplateClassResolver#UNRESTRICTED_RESOLVER} in * FreeMarker 2.3.x, and {@link TemplateClassResolver#SAFER_RESOLVER} * starting from FreeMarker 2.4.0. If you allow users to upload templates, * it's important to use a custom restrictive {@link TemplateClassResolver}. * * @since 2.3.17 */ public void setNewBuiltinClassResolver(TemplateClassResolver newBuiltinClassResolver) { if (newBuiltinClassResolver == null) throw new IllegalArgumentException( "Setting \"" + NEW_BUILTIN_CLASS_RESOLVER_KEY + "\" can't be null."); this.newBuiltinClassResolver = newBuiltinClassResolver; properties.setProperty(NEW_BUILTIN_CLASS_RESOLVER_KEY, newBuiltinClassResolver.getClass().getName()); } /** * Retrieves the {@link TemplateClassResolver} used * to resolve classes when "SomeClassName"?new is called in a template. * * @since 2.3.17 */ public TemplateClassResolver getNewBuiltinClassResolver() { return newBuiltinClassResolver != null ? newBuiltinClassResolver : parent.getNewBuiltinClassResolver(); } /** * Sets whether the output {@link Writer} is automatically flushed at * the end of {@link Template#process(Object, Writer)} (and its * overloads). The default is {@code true}. * *

Using {@code false} is needed for example when a Web page is composed * from several boxes (like portlets, GUI panels, etc.) that aren't inserted * with #include (or with similar directives) into a master * FreeMarker template, rather they are all processed with a separate * {@link Template#process(Object, Writer)} call. In a such scenario the * automatic flushes would commit the HTTP response after each box, hence * interfering with full-page buffering, and also possibly decreasing * performance with too frequent and too early response buffer flushes. * * @since 2.3.17 */ public void setAutoFlush(boolean autoFlush) { this.autoFlush = autoFlush ? Boolean.TRUE : Boolean.FALSE; properties.setProperty(AUTO_FLUSH_KEY, String.valueOf(autoFlush)); } /** * See {@link #setAutoFlush(boolean)} * * @since 2.3.17 */ public boolean getAutoFlush() { return autoFlush != null ? autoFlush.booleanValue() : (parent != null ? parent.getAutoFlush() : true); } private static final String ALLOWED_CLASSES = "allowed_classes"; private static final String TRUSTED_TEMPLATES = "trusted_templates"; /** * Sets a setting by a name and string value. * *

List of supported names and their valid values: *

    *
  • "locale": local codes with the usual format, such as "en_US". *
  • "classic_compatible": * "true", "false", "yes", "no", * "t", "f", "y", "n". * Case insensitive. *
  • "template_exception_handler": If the value contains dot, then it is * interpreted as class name, and the object will be created with * its parameterless constructor. If the value does not contain dot, * then it must be one of these special values: * "rethrow", "debug", * "html_debug", "ignore" (case insensitive). *
  • "arithmetic_engine": If the value contains dot, then it is * interpreted as class name, and the object will be created with * its parameterless constructor. If the value does not contain dot, * then it must be one of these special values: * "bigdecimal", "conservative" (case insensitive). *
  • "object_wrapper": If the value contains dot, then it is * interpreted as class name, and the object will be created with * its parameterless constructor. If the value does not contain dot, * then it must be one of these special values: * "simple", "beans", "jython" (case insensitive). *
  • "number_format": pattern as java.text.DecimalFormat defines. *
  • "boolean_format": the textual value for boolean true and false, * separated with comma. For example "yes,no". *
  • "date_format", "time_format", "datetime_format": patterns as * java.text.SimpleDateFormat defines. *
  • "time_zone": time zone, with the format as * java.util.TimeZone.getTimeZone defines. For example "GMT-8:00" or * "America/Los_Angeles" *
  • "output_encoding": Informs FreeMarker about the charset * used for the output. As FreeMarker outputs character stream (not * byte stream), it is not aware of the output charset unless the * software that encloses it tells it explicitly with this setting. * Some templates may use FreeMarker features that require this. *
  • "url_escaping_charset": If this setting is set, then it * overrides the value of the "output_encoding" setting when * FreeMarker does URL encoding. *
  • "auto_flush": see {@link #setAutoFlush(boolean)}. * Since 2.3.17. *
  • "new_builtin_class_resolver": * see {@link #setNewBuiltinClassResolver(TemplateClassResolver)}. * Since 2.3.17. The value must be one of these (ignore the * quotation marks): *
      *
    1. "unrestricted": * Use {@link TemplateClassResolver#UNRESTRICTED_RESOLVER} *
    2. "safer": * Use {@link TemplateClassResolver#SAFER_RESOLVER} *
    3. "allows_nothing": * Use {@link TemplateClassResolver#ALLOWS_NOTHING_RESOLVER} *
    4. Something that contains colon will use * {@link OptInTemplateClassResolver} and is expected to * store comma separated values (possibly quoted) segmented * with "allowed_classes:" and/or * "trusted_templates:". Examples of valid values: * * * * * * *
      Setting value * Meaning *
      allowed_classes: com.example.C1, com.example.C2, * trusted_templates: lib/*, safe.ftl * * Only allow instantiating the com.example.C1 and * com.example.C2 classes. But, allow templates * within the lib/ directory (like * lib/foo/bar.ftl) and template safe.ftl * (that does not match foo/safe.ftl, only * exactly safe.ftl) to instantiate anything * that {@link TemplateClassResolver#SAFER_RESOLVER} allows. *
      * allowed_classes: com.example.C1, com.example.C2 * Only allow instantiating the com.example.C1 and * com.example.C2 classes. There are no * trusted templates. *
      trusted_templates: lib/*, safe.ftl * * Do not allow instantiating any classes, except in * templates inside lib/ or in template * safe.ftl. *
      * For more details see {@link OptInTemplateClassResolver}. *
    5. Otherwise if the value contains dot, it's interpreted as * a full-qualified class name, and the object will be created * with its parameterless constructor. *
    *
* * @param key the name of the setting. * @param value the string that describes the new value of the setting. * * @throws UnknownSettingException if the key is wrong. * @throws TemplateException if the new value of the setting can't be set * for any other reasons. */ public void setSetting(String key, String value) throws TemplateException { try { if (LOCALE_KEY.equals(key)) { setLocale(StringUtil.deduceLocale(value)); } else if (NUMBER_FORMAT_KEY.equals(key)) { setNumberFormat(value); } else if (TIME_FORMAT_KEY.equals(key)) { setTimeFormat(value); } else if (DATE_FORMAT_KEY.equals(key)) { setDateFormat(value); } else if (DATETIME_FORMAT_KEY.equals(key)) { setDateTimeFormat(value); } else if (TIME_ZONE_KEY.equals(key)) { setTimeZone(TimeZone.getTimeZone(value)); } else if (CLASSIC_COMPATIBLE_KEY.equals(key)) { setClassicCompatible(StringUtil.getYesNo(value)); } else if (TEMPLATE_EXCEPTION_HANDLER_KEY.equals(key)) { if (value.indexOf('.') == -1) { if ("debug".equalsIgnoreCase(value)) { setTemplateExceptionHandler( TemplateExceptionHandler.DEBUG_HANDLER); } else if ("html_debug".equalsIgnoreCase(value)) { setTemplateExceptionHandler( TemplateExceptionHandler.HTML_DEBUG_HANDLER); } else if ("ignore".equalsIgnoreCase(value)) { setTemplateExceptionHandler( TemplateExceptionHandler.IGNORE_HANDLER); } else if ("rethrow".equalsIgnoreCase(value)) { setTemplateExceptionHandler( TemplateExceptionHandler.RETHROW_HANDLER); } else { throw invalidSettingValueException(key, value); } } else { setTemplateExceptionHandler( (TemplateExceptionHandler) ClassUtil.forName(value) .newInstance()); } } else if (ARITHMETIC_ENGINE_KEY.equals(key)) { if (value.indexOf('.') == -1) { if ("bigdecimal".equalsIgnoreCase(value)) { setArithmeticEngine(ArithmeticEngine.BIGDECIMAL_ENGINE); } else if ("conservative".equalsIgnoreCase(value)) { setArithmeticEngine(ArithmeticEngine.CONSERVATIVE_ENGINE); } else { throw invalidSettingValueException(key, value); } } else { setArithmeticEngine( (ArithmeticEngine) ClassUtil.forName(value) .newInstance()); } } else if (OBJECT_WRAPPER_KEY.equals(key)) { if (value.indexOf('.') == -1) { if ("default".equalsIgnoreCase(value)) { setObjectWrapper(ObjectWrapper.DEFAULT_WRAPPER); } else if ("simple".equalsIgnoreCase(value)) { setObjectWrapper(ObjectWrapper.SIMPLE_WRAPPER); } else if ("beans".equalsIgnoreCase(value)) { setObjectWrapper(ObjectWrapper.BEANS_WRAPPER); } else if ("jython".equalsIgnoreCase(value)) { Class clazz = Class.forName( "freemarker.ext.jython.JythonWrapper"); setObjectWrapper( (ObjectWrapper) clazz.getField("INSTANCE").get(null)); } else { throw invalidSettingValueException(key, value); } } else { setObjectWrapper((ObjectWrapper) ClassUtil.forName(value) .newInstance()); } } else if (BOOLEAN_FORMAT_KEY.equals(key)) { setBooleanFormat(value); } else if (OUTPUT_ENCODING_KEY.equals(key)) { setOutputEncoding(value); } else if (URL_ESCAPING_CHARSET_KEY.equals(key)) { setURLEscapingCharset(value); } else if (STRICT_BEAN_MODELS.equals(key)) { setStrictBeanModels(StringUtil.getYesNo(value)); } else if (AUTO_FLUSH_KEY.equals(key)) { setAutoFlush(StringUtil.getYesNo(value)); } else if (NEW_BUILTIN_CLASS_RESOLVER_KEY.equals(key)) { if ("unrestricted".equals(value)) { setNewBuiltinClassResolver(TemplateClassResolver.UNRESTRICTED_RESOLVER); } else if ("safer".equals(value)) { setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER); } else if ("allows_nothing".equals(value)) { setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER); } else if (value.indexOf(":") != -1) { List segments = parseAsSegmentedList(value); Set allowedClasses = null; List trustedTemplates = null; for (int i = 0; i < segments.size(); i++) { KeyValuePair kv = (KeyValuePair) segments.get(i); String segmentKey = (String) kv.getKey(); List segmentValue = (List) kv.getValue(); if (segmentKey.equals(ALLOWED_CLASSES)) { allowedClasses = new HashSet(segmentValue); } else if (segmentKey.equals(TRUSTED_TEMPLATES)) { trustedTemplates = segmentValue; } else { throw new ParseException( "Unrecognized list segment key: " + StringUtil.jQuote(segmentKey) + ". Supported keys are: \"" + ALLOWED_CLASSES + "\", \"" + TRUSTED_TEMPLATES + "\"", 0, 0); } } setNewBuiltinClassResolver( new OptInTemplateClassResolver(allowedClasses, trustedTemplates)); } else if (value.indexOf('.') == -1) { setNewBuiltinClassResolver((TemplateClassResolver) ClassUtil.forName(value) .newInstance()); } else { throw invalidSettingValueException(key, value); } } else { throw unknownSettingException(key); } } catch(Exception e) { throw new TemplateException( "Failed to set setting " + StringUtil.jQuote(key) + " to value " + StringUtil.jQuote(value) + "; see cause exception.", e, getEnvironment()); } } public void setStrictBeanModels(boolean strict) { if (!(objectWrapper instanceof BeansWrapper)) { throw new IllegalStateException("The value of the " + OBJECT_WRAPPER_KEY + " setting isn't a " + BeansWrapper.class.getName() + "."); } ((BeansWrapper) objectWrapper).setStrict(strict); } /** * Returns the textual representation of a setting. * @param key the setting key. Can be any of standard XXX_KEY * constants, or a custom key. * * @deprecated This method was always defective, and certainly it always * will be. Don't use it. (Simply, it's hardly possible in general to * convert setting values to text in a way that ensures that * {@link #setSetting(String, String)} will work with them correctly.) */ public String getSetting(String key) { return properties.getProperty(key); } /** * This meant to return the String-to-String Map of the * settings. So it actually should return a Properties object, * but it doesn't by mistake. The returned Map is read-only, * but it will reflect the further configuration changes (aliasing effect). * * @deprecated This method was always defective, and certainly it always * will be. Don't use it. (Simply, it's hardly possible in general to * convert setting values to text in a way that ensures that * {@link #setSettings(Properties)} will work with them correctly.) */ public Map getSettings() { return Collections.unmodifiableMap(properties); } protected Environment getEnvironment() { return this instanceof Environment ? (Environment) this : Environment.getCurrentEnvironment(); } protected TemplateException unknownSettingException(String name) { return new UnknownSettingException(name, getEnvironment()); } protected TemplateException invalidSettingValueException(String name, String value) { return new TemplateException("Invalid value for setting " + name + ": " + value, getEnvironment()); } public static class UnknownSettingException extends TemplateException { private UnknownSettingException(String name, Environment env) { super("Unknown setting: " + name, env); } } /** * Set the settings stored in a Properties object. * * @throws TemplateException if the Properties object contains * invalid keys, or invalid setting values, or any other error occurs * while changing the settings. */ public void setSettings(Properties props) throws TemplateException { Iterator it = props.keySet().iterator(); while (it.hasNext()) { String key = (String) it.next(); setSetting(key, props.getProperty(key).trim()); } } /** * Reads a setting list (key and element pairs) from the input stream. * The stream has to follow the usual .properties format. * * @throws TemplateException if the stream contains * invalid keys, or invalid setting values, or any other error occurs * while changing the settings. * @throws IOException if an error occurred when reading from the input stream. */ public void setSettings(InputStream propsIn) throws TemplateException, IOException { Properties p = new Properties(); p.load(propsIn); setSettings(p); } /** * Internal entry point for setting unnamed custom attributes */ void setCustomAttribute(Object key, Object value) { synchronized(customAttributes) { customAttributes.put(key, value); } } /** * Internal entry point for getting unnamed custom attributes */ Object getCustomAttribute(Object key, CustomAttribute attr) { synchronized(customAttributes) { Object o = customAttributes.get(key); if(o == null && !customAttributes.containsKey(key)) { o = attr.create(); customAttributes.put(key, o); } return o; } } /** * Sets a named custom attribute for this configurable. * * @param name the name of the custom attribute * @param value the value of the custom attribute. You can set the value to * null, however note that there is a semantic difference between an * attribute set to null and an attribute that is not present, see * {@link #removeCustomAttribute(String)}. */ public void setCustomAttribute(String name, Object value) { synchronized(customAttributes) { customAttributes.put(name, value); } } /** * Returns an array with names of all custom attributes defined directly * on this configurable. (That is, it doesn't contain the names of custom attributes * defined indirectly on its parent configurables.) The returned array is never null, * but can be zero-length. * The order of elements in the returned array is not defined and can change * between invocations. */ public String[] getCustomAttributeNames() { synchronized(customAttributes) { Collection names = new LinkedList(customAttributes.keySet()); for (Iterator iter = names.iterator(); iter.hasNext();) { if(!(iter.next() instanceof String)) { iter.remove(); } } return (String[])names.toArray(new String[names.size()]); } } /** * Removes a named custom attribute for this configurable. Note that this * is different than setting the custom attribute value to null. If you * set the value to null, {@link #getCustomAttribute(String)} will return * null, while if you remove the attribute, it will return the value of * the attribute in the parent configurable (if there is a parent * configurable, that is). * * @param name the name of the custom attribute */ public void removeCustomAttribute(String name) { synchronized(customAttributes) { customAttributes.remove(name); } } /** * Retrieves a named custom attribute for this configurable. If the * attribute is not present in the configurable, and the configurable has * a parent, then the parent is looked up as well. * * @param name the name of the custom attribute * * @return the value of the custom attribute. Note that if the custom attribute * was created with <#ftl attributes={...}>, then this value is already * unwrapped (i.e. it's a String, or a List, or a * Map, ...etc., not a FreeMarker specific class). */ public Object getCustomAttribute(String name) { Object retval; synchronized(customAttributes) { retval = customAttributes.get(name); if(retval == null && customAttributes.containsKey(name)) { return null; } } if(retval == null && parent != null) { return parent.getCustomAttribute(name); } return retval; } protected void doAutoImportsAndIncludes(Environment env) throws TemplateException, IOException { if(parent != null) parent.doAutoImportsAndIncludes(env); } protected ArrayList parseAsList(String text) throws ParseException { return new SettingStringParser(text).parseAsList(); } protected ArrayList parseAsSegmentedList(String text) throws ParseException { return new SettingStringParser(text).parseAsSegmentedList(); } protected HashMap parseAsImportList(String text) throws ParseException { return new SettingStringParser(text).parseAsImportList(); } private static class KeyValuePair { private final Object key; private final Object value; KeyValuePair(Object key, Object value) { this.key = key; this.value = value; } Object getKey() { return key; } Object getValue() { return value; } } /** * Helper class for parsing setting values given with string. */ private static class SettingStringParser { private String text; private int p; private int ln; private SettingStringParser(String text) { this.text = text; this.p = 0; this.ln = text.length(); } ArrayList parseAsSegmentedList() throws ParseException { ArrayList segments = new ArrayList(); ArrayList currentSegment = null; char c; while (true) { c = skipWS(); if (c == ' ') break; String item = fetchStringValue(); c = skipWS(); if (c == ':') { currentSegment = new ArrayList(); segments.add(new KeyValuePair(item, currentSegment)); } else { if (currentSegment == null) { throw new ParseException( "The very first list item must be followed by \":\" so " + "it will be the key for the following sub-list.", 0, 0); } currentSegment.add(item); } if (c == ' ') break; if (c != ',' && c != ':') throw new ParseException( "Expected \",\" or \":\" or the end of text but " + "found \"" + c + "\"", 0, 0); p++; } return segments; } ArrayList parseAsList() throws ParseException { char c; ArrayList seq = new ArrayList(); while (true) { c = skipWS(); if (c == ' ') break; seq.add(fetchStringValue()); c = skipWS(); if (c == ' ') break; if (c != ',') throw new ParseException( "Expected \",\" or the end of text but " + "found \"" + c + "\"", 0, 0); p++; } return seq; } HashMap parseAsImportList() throws ParseException { char c; HashMap map = new HashMap(); while (true) { c = skipWS(); if (c == ' ') break; String lib = fetchStringValue(); c = skipWS(); if (c == ' ') throw new ParseException( "Unexpected end of text: expected \"as\"", 0, 0); String s = fetchKeyword(); if (!s.equalsIgnoreCase("as")) throw new ParseException( "Expected \"as\", but found " + StringUtil.jQuote(s), 0, 0); c = skipWS(); if (c == ' ') throw new ParseException( "Unexpected end of text: expected gate hash name", 0, 0); String ns = fetchStringValue(); map.put(ns, lib); c = skipWS(); if (c == ' ') break; if (c != ',') throw new ParseException( "Expected \",\" or the end of text but " + "found \"" + c + "\"", 0, 0); p++; } return map; } String fetchStringValue() throws ParseException { String w = fetchWord(); if (w.startsWith("'") || w.startsWith("\"")) { w = w.substring(1, w.length() - 1); } return StringUtil.FTLStringLiteralDec(w); } String fetchKeyword() throws ParseException { String w = fetchWord(); if (w.startsWith("'") || w.startsWith("\"")) { throw new ParseException( "Keyword expected, but a string value found: " + w, 0, 0); } return w; } char skipWS() { char c; while (p < ln) { c = text.charAt(p); if (!Character.isWhitespace(c)) return c; p++; } return ' '; } private String fetchWord() throws ParseException { if (p == ln) throw new ParseException( "Unexpeced end of text", 0, 0); char c = text.charAt(p); int b = p; if (c == '\'' || c == '"') { boolean escaped = false; char q = c; p++; while (p < ln) { c = text.charAt(p); if (!escaped) { if (c == '\\') { escaped = true; } else if (c == q) { break; } } else { escaped = false; } p++; } if (p == ln) { throw new ParseException("Missing " + q, 0, 0); } p++; return text.substring(b, p); } else { do { c = text.charAt(p); if (!(Character.isLetterOrDigit(c) || c == '/' || c == '\\' || c == '_' || c == '.' || c == '-' || c == '!' || c == '*' || c == '?')) break; p++; } while (p < ln); if (b == p) { throw new ParseException("Unexpected character: " + c, 0, 0); } else { return text.substring(b, p); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Range.java0000644000175000017500000001011211723544471023372 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * A class that represents a Range between two integers. */ final class Range extends Expression { final Expression left; final Expression right; Range(Expression left, Expression right) { this.left = left; this.right = right; } boolean hasRhs() { return right != null; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { int min = EvaluationUtil.getNumber(left, env).intValue(); int max = 0; if (right != null) { max = EvaluationUtil.getNumber(right, env).intValue(); return new NumericalRange(min, max); } return new NumericalRange(min); } boolean isTrue(Environment env) throws TemplateException { String msg = "Error " + getStartLocation() + ". " + "\nExpecting a boolean here." + " Expression " + this + " is a range."; throw new NonBooleanException(msg, env); } public String getCanonicalForm() { String rhs = right != null ? right.getCanonicalForm() : ""; return left.getCanonicalForm() + ".." + rhs; } boolean isLiteral() { boolean rightIsLiteral = right == null || right.isLiteral(); return constantValue != null || (left.isLiteral() && rightIsLiteral); } Expression _deepClone(String name, Expression subst) { return new Range(left.deepClone(name, subst), right.deepClone(name, subst)); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/ComparisonExpression.java0000644000175000017500000002233411723544470026540 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.Date; import freemarker.template.*; /** * A class that handles comparisons. * @author Jonathan Revusky * @author Attila Szegedi */ final class ComparisonExpression extends BooleanExpression { static final int EQUALS=1; static final int NOT_EQUALS=2; static final int LESS_THAN=3; static final int GREATER_THAN=4; static final int LESS_THAN_EQUALS=5; static final int GREATER_THAN_EQUALS=6; private final Expression left; private final Expression right; private final int operation; private final String opString; ComparisonExpression(Expression left, Expression right, String opString) { this.left = left; this.right = right; opString = opString.intern(); this.opString = opString; if (opString == "==" || opString == "=") { operation = EQUALS; } else if (opString == "!=") { operation = NOT_EQUALS; } else if (opString == "gt" || opString == "\\gt" || opString == ">" || opString == ">") { operation = GREATER_THAN; } else if (opString == "gte" || opString == "\\gte" || opString == ">=" || opString == ">=") { operation = GREATER_THAN_EQUALS; } else if (opString== "lt" || opString == "\\lt" || opString == "<" || opString == "<") { operation = LESS_THAN; } else if (opString == "lte" || opString == "\\lte" || opString == "<=" || opString == "<=") { operation = LESS_THAN_EQUALS; } else { throw new RuntimeException("Unknown comparison operator " + opString); } } /* * WARNING! This algorithm is duplicated in SequenceBuiltins.modelsEqual. * Thus, if you update this method, then you have to update that too! */ boolean isTrue(Environment env) throws TemplateException { TemplateModel ltm = left.getAsTemplateModel(env); TemplateModel rtm = right.getAsTemplateModel(env); if (env != null && env.isClassicCompatible()) { if (ltm == null) { ltm = TemplateScalarModel.EMPTY_STRING; } if (rtm == null) { rtm = TemplateScalarModel.EMPTY_STRING; } } assertNonNull(ltm, left, env); assertNonNull(rtm, right, env); int comp = 0; if(ltm instanceof TemplateNumberModel && rtm instanceof TemplateNumberModel) { Number first = EvaluationUtil.getNumber((TemplateNumberModel)ltm, left, env); Number second = EvaluationUtil.getNumber((TemplateNumberModel)rtm, right, env); ArithmeticEngine ae = env != null ? env.getArithmeticEngine() : getTemplate().getArithmeticEngine(); comp = ae.compareNumbers(first, second); } else if(ltm instanceof TemplateDateModel && rtm instanceof TemplateDateModel) { TemplateDateModel ltdm = (TemplateDateModel)ltm; TemplateDateModel rtdm = (TemplateDateModel)rtm; int ltype = ltdm.getDateType(); int rtype = rtdm.getDateType(); if(ltype != rtype) { throw new TemplateException( "Can not compare dates of different type. Left date is of " + TemplateDateModel.TYPE_NAMES.get(ltype) + " type, right date is of " + TemplateDateModel.TYPE_NAMES.get(rtype) + " type.", env); } if(ltype == TemplateDateModel.UNKNOWN) { throw new TemplateException( "Left date is of UNKNOWN type, and can not be compared.", env); } if(rtype == TemplateDateModel.UNKNOWN) { throw new TemplateException( "Right date is of UNKNOWN type, and can not be compared.", env); } Date first = EvaluationUtil.getDate(ltdm, left, env); Date second = EvaluationUtil.getDate(rtdm, right, env); comp = first.compareTo(second); } else if(ltm instanceof TemplateScalarModel && rtm instanceof TemplateScalarModel) { if(operation != EQUALS && operation != NOT_EQUALS) { throw new TemplateException("Can not use operator " + opString + " on string values.", env); } String first = EvaluationUtil.getString((TemplateScalarModel)ltm, left, env); String second = EvaluationUtil.getString((TemplateScalarModel)rtm, right, env); comp = env.getCollator().compare(first, second); } else if(ltm instanceof TemplateBooleanModel && rtm instanceof TemplateBooleanModel) { if(operation != EQUALS && operation != NOT_EQUALS) { throw new TemplateException("Can not use operator " + opString + " on boolean values.", env); } boolean first = ((TemplateBooleanModel)ltm).getAsBoolean(); boolean second = ((TemplateBooleanModel)rtm).getAsBoolean(); comp = (first ? 1 : 0) - (second ? 1 : 0); } // Here we handle compatibility issues else if(env.isClassicCompatible()) { String first = left.getStringValue(env); String second = right.getStringValue(env); comp = env.getCollator().compare(first, second); } else { throw new TemplateException( "The only legal comparisons are between two numbers, two strings, or two dates.\n" + "Left hand operand is a " + ltm.getClass().getName() + "\n" + "Right hand operand is a " + rtm.getClass().getName() + "\n" , env); } switch (operation) { case EQUALS: return comp == 0; case NOT_EQUALS: return comp != 0; case LESS_THAN : return comp < 0; case GREATER_THAN : return comp > 0; case LESS_THAN_EQUALS : return comp <= 0; case GREATER_THAN_EQUALS : return comp >= 0; default : throw new TemplateException("unknown operation", env); } } public String getCanonicalForm() { return left.getCanonicalForm() + ' ' + opString + ' ' + right.getCanonicalForm(); } boolean isLiteral() { return constantValue != null || (left.isLiteral() && right.isLiteral()); } Expression _deepClone(String name, Expression subst) { return new ComparisonExpression(left.deepClone(name, subst), right.deepClone(name, subst), opString); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/OptInTemplateClassResolver.java0000644000175000017500000001441611723544471027606 0ustar ebourgebourgpackage freemarker.core; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.StringUtil; /** * A {@link TemplateClassResolver} that resolves only the classes whose name * was specified in the constructor. */ public class OptInTemplateClassResolver implements TemplateClassResolver { private final Set/**/ allowedClasses; private final List/**/ trustedTemplatePrefixes; private final Set/**/ trustedTemplateNames; /** * Creates a new instance. * * @param allowedClasses the {@link Set} of {@link String}-s that contains * the full-qualified names of the allowed classes. * Can be null (means not class is allowed). * @param trustedTemplates the {@link List} of {@link String}-s that contains * template names (i.e., template root directory relative paths) * and prefix patterns (like "include/*") of templates * for which {@link TemplateClassResolver#SAFER_RESOLVER} will be * used (which is not as safe as {@link OptInTemplateClassResolver}). * The list items need not start with "/" (if they are, it * will be removed). List items ending with "*" are treated * as prefixes (i.e. "foo*" matches "foobar", * "foo/bar/baaz", "foowhatever/bar/baaz", * etc.). The "*" has no special meaning anywhere else. * The matched template name is the name (template root directory * relative path) of the template that directly (lexically) contains the * operation (like ?new) that wants to get the class. Thus, * if a trusted template includes a non-trusted template, the * allowedClasses restriction will apply in the included * template. * This parameter can be null (means no trusted templates). */ public OptInTemplateClassResolver( Set allowedClasses, List trustedTemplates) { this.allowedClasses = allowedClasses != null ? allowedClasses : Collections.EMPTY_SET; if (trustedTemplates != null) { trustedTemplateNames = new HashSet(); trustedTemplatePrefixes = new ArrayList(); Iterator it = trustedTemplates.iterator(); while (it.hasNext()) { String li = (String) it.next(); if (li.startsWith("/")) li = li.substring(1); if (li.endsWith("*")) { trustedTemplatePrefixes.add(li.substring(0, li.length() - 1)); } else { trustedTemplateNames.add(li); } } } else { trustedTemplateNames = Collections.EMPTY_SET; trustedTemplatePrefixes = Collections.EMPTY_LIST; } } public Class resolve(String className, Environment env, Template template) throws TemplateException { String templateName = safeGetTemplateName(template); if (templateName != null && (trustedTemplateNames.contains(templateName) || hasMatchingPrefix(templateName))) { return TemplateClassResolver.SAFER_RESOLVER.resolve(className, env, template); } else { if (!allowedClasses.contains(className)) { throw new TemplateException( "Instantiating " + className + " is not allowed in the " + "template for security reasons. (If you meet this problem " + "when using ?new in a template, you may want to look " + "at the \"" + Configurable.NEW_BUILTIN_CLASS_RESOLVER_KEY + "\" setting in the FreeMarker configuration.)", env); } else { try { return ClassUtil.forName(className); } catch (ClassNotFoundException e) { throw new TemplateException(e, env); } } } } /** * Extract the template name from the template object which will be matched * against the trusted template names and pattern. */ protected String safeGetTemplateName(Template template) { if (template == null) return null; String name = template.getName(); if (name == null) return null; // Detect exploits, return null if one is suspected: String decodedName = name; if (decodedName.indexOf('%') != -1) { decodedName = StringUtil.replace(decodedName, "%2e", ".", false, false); decodedName = StringUtil.replace(decodedName, "%2E", ".", false, false); decodedName = StringUtil.replace(decodedName, "%2f", "/", false, false); decodedName = StringUtil.replace(decodedName, "%2F", "/", false, false); decodedName = StringUtil.replace(decodedName, "%5c", "\\", false, false); decodedName = StringUtil.replace(decodedName, "%5C", "\\", false, false); } int dotDotIdx = decodedName.indexOf(".."); if (dotDotIdx != -1) { int before = dotDotIdx - 1 >= 0 ? decodedName.charAt(dotDotIdx - 1) : -1; int after = dotDotIdx + 2 < decodedName.length() ? decodedName.charAt(dotDotIdx + 2) : -1; if ((before == -1 || before == '/' || before == '\\') && (after == -1 || after == '/' || after == '\\')) { return null; } } return name.startsWith("/") ? name.substring(1) : name; } private boolean hasMatchingPrefix(String name) { for (int i = 0; i < trustedTemplatePrefixes.size(); i++) { String prefix = (String) trustedTemplatePrefixes.get(i); if (name.startsWith(prefix)) return true; } return false; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/UnifiedCall.java0000644000175000017500000001665611723544471024540 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.*; import java.util.*; import freemarker.template.*; /** * An element for the unified macro/transform syntax. */ final class UnifiedCall extends TemplateElement { private Expression nameExp; private Map namedArgs; private List positionalArgs, bodyParameterNames; boolean legacySyntax; UnifiedCall(Expression nameExp, Map namedArgs, TemplateElement nestedBlock, List bodyParameterNames) { this.nameExp = nameExp; this.namedArgs = namedArgs; this.nestedBlock = nestedBlock; this.bodyParameterNames = bodyParameterNames; } UnifiedCall(Expression nameExp, List positionalArgs, TemplateElement nestedBlock, List bodyParameterNames) { this.nameExp = nameExp; this.positionalArgs = positionalArgs; if (nestedBlock == TextBlock.EMPTY_BLOCK) { nestedBlock = null; } this.nestedBlock = nestedBlock; this.bodyParameterNames = bodyParameterNames; } void accept(Environment env) throws TemplateException, IOException { TemplateModel tm = nameExp.getAsTemplateModel(env); if (tm == Macro.DO_NOTHING_MACRO) return; // shortcut here. if (tm instanceof Macro) { Macro macro = (Macro) tm; if (macro.isFunction && !legacySyntax) { throw new TemplateException("Routine " + macro.getName() + " is a function. A function can only be called " + "within the evaluation of an expression.", env); } env.visit(macro, namedArgs, positionalArgs, bodyParameterNames, nestedBlock); } else { boolean isDirectiveModel = tm instanceof TemplateDirectiveModel; if (isDirectiveModel || tm instanceof TemplateTransformModel) { Map args; if (namedArgs != null && !namedArgs.isEmpty()) { args = new HashMap(); for (Iterator it = namedArgs.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String key = (String) entry.getKey(); Expression valueExp = (Expression) entry.getValue(); TemplateModel value = valueExp.getAsTemplateModel(env); args.put(key, value); } } else { args = EmptyMap.instance; } if(isDirectiveModel) { env.visit(nestedBlock, (TemplateDirectiveModel) tm, args, bodyParameterNames); } else { env.visit(nestedBlock, (TemplateTransformModel) tm, args); } } else if (tm == null) { throw new InvalidReferenceException(this.getStartLocation() + " " + nameExp + " not found.", env); } else { throw new TemplateException(getStartLocation() + ": " + nameExp + " is not a user-defined directive. It is a " + tm.getClass().getName(), env); } } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<@"); buf.append(nameExp.getCanonicalForm()); if (positionalArgs != null) { for (int i=0; i'); buf.append(nestedBlock.getCanonicalForm()); buf.append("'); } return buf.toString(); } public String getDescription() { return "user-directive " + nameExp; } /* //REVISIT boolean heedsOpeningWhitespace() { return nestedBlock == null; } //REVISIT boolean heedsTrailingWhitespace() { return nestedBlock == null; }*/ } libfreemarker-java-2.3.19.orig/src/freemarker/core/LocalContext.java0000644000175000017500000000606211723544470024745 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.Collection; import freemarker.template.*; /** * An interface that represents a local context. This is used as the abstraction for * the context of a Macro invocation, a loop, or the nested block call from within * a macro. * Jonathan Revusky */ public interface LocalContext { TemplateModel getLocalVariable(String name) throws TemplateModelException; Collection getLocalVariableNames() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/core/Node.java0000644000175000017500000000237711723544471023241 0ustar ebourgebourg/* Generated By:FreeCC 0.90: Do not edit. Node.java.java */ package freemarker.core; public interface Node { /** This method is called after the node has been made the current * node. It indicates that child nodes can now be added to it. */ void jjtOpen(); /** * This method is called after all the child nodes have been * added. */ void jjtClose(); /** * This pair of methods are used to inform the node of its * parent. */ void jjtSetParent(Node n); Node jjtGetParent(); /** This method tells the node to add its argument to the node's list of children. */ void jjtAddChild(Node n, int i); /** This method returns a child node. The children are numbered from zero, left to right. */ Node jjtGetChild(int i); /** * Return the number of children the node has. */ int jjtGetNumChildren(); String getInputSource(); void setInputSource(String inputSource); int getBeginLine(); int getEndLine(); int getBeginColumn(); int getEndColumn(); void setBeginLine(int beginLine); void setEndLine(int endLine); void setBeginColumn(int beginColumn); void setEndColumn(int endColumn); } libfreemarker-java-2.3.19.orig/src/freemarker/core/RecoveryBlock.java0000644000175000017500000000637711723544471025131 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.*; final class RecoveryBlock extends TemplateElement { RecoveryBlock(TemplateElement block) { this.nestedBlock = block; } void accept(Environment env) throws TemplateException, IOException { if (nestedBlock != null) { env.visit(nestedBlock); } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#recover>"); if (nestedBlock != null) { buf.append(nestedBlock.getCanonicalForm()); } buf.append("/#recover"); return buf.toString(); } public String getDescription() { return "recover block"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TokenMgrError.java0000644000175000017500000001036311723544471025106 0ustar ebourgebourg/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ package freemarker.core; public class TokenMgrError extends Error { /* * Ordinals for various reasons why an Error of this type can be thrown. */ /** * Lexical error occured. */ static final int LEXICAL_ERROR = 0; /** * An attempt wass made to create a second instance of a static token manager. */ static final int STATIC_LEXER_ERROR = 1; /** * Tried to change to an invalid lexical state. */ static final int INVALID_LEXICAL_STATE = 2; /** * Detected (and bailed out of) an infinite loop in the token manager. */ static final int LOOP_DETECTED = 3; /** * Indicates the reason why the exception is thrown. It will have * one of the above 4 values. */ int errorCode; /** * Replaces unprintable characters by their espaced (or unicode escaped) * equivalents in the given string */ protected static final String addEscapes(String str) { StringBuffer retval = new StringBuffer(); char ch; for (int i = 0; i < str.length(); i++) { switch (str.charAt(i)) { case 0 : continue; case '\b': retval.append("\\b"); continue; case '\t': retval.append("\\t"); continue; case '\n': retval.append("\\n"); continue; case '\f': retval.append("\\f"); continue; case '\r': retval.append("\\r"); continue; case '\"': retval.append("\\\""); continue; case '\'': retval.append("\\\'"); continue; case '\\': retval.append("\\\\"); continue; default: if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { String s = "0000" + Integer.toString(ch, 16); retval.append("\\u" + s.substring(s.length() - 4, s.length())); } else { retval.append(ch); } continue; } } return retval.toString(); } /** * Returns a detailed message for the Error when it is thrown by the * token manager to indicate a lexical error. * Parameters : * EOFSeen : indicates if EOF caused the lexicl error * curLexState : lexical state in which this error occured * errorLine : line number when the error occured * errorColumn : column number when the error occured * errorAfter : prefix that was seen before this error occured * curchar : the offending character * Note: You can customize the lexical error message by modifying this method. */ protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { return("Lexical error at line " + errorLine + ", column " + errorColumn + ". Encountered: " + (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + "after : \"" + addEscapes(errorAfter) + "\""); } /** * You can also modify the body of this method to customize your error messages. * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not * of end-users concern, so you can return something like : * * "Internal Error : Please file a bug report .... " * * from this method for such cases in the release version of your parser. */ public String getMessage() { return super.getMessage(); } /* * Constructors of various flavors follow. */ public TokenMgrError() { } public TokenMgrError(String message, int reason) { super(message); errorCode = reason; } public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BuiltinVariable.java0000644000175000017500000001562611723544470025430 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; import freemarker.template.*; /** * A reference to a built-in identifier, such as .root */ final class BuiltinVariable extends Expression { static final String TEMPLATE_NAME = "template_name"; static final String NAMESPACE = "namespace"; static final String MAIN = "main"; static final String GLOBALS = "globals"; static final String LOCALS = "locals"; static final String DATA_MODEL = "data_model"; static final String LANG = "lang"; static final String LOCALE = "locale"; static final String CURRENT_NODE = "current_node"; static final String NODE = "node"; static final String PASS = "pass"; static final String VARS = "vars"; static final String VERSION = "version"; static final String ERROR = "error"; static final String OUTPUT_ENCODING = "output_encoding"; static final String URL_ESCAPING_CHARSET = "url_escaping_charset"; static final String NOW = "now"; private final String name; BuiltinVariable(String name) throws ParseException { name = name.intern(); this.name = name; if (name != TEMPLATE_NAME && name != NAMESPACE && name != MAIN && name != GLOBALS && name != LOCALS && name != LANG && name != LOCALE && name != DATA_MODEL && name != CURRENT_NODE && name != NODE && name != PASS && name != VARS && name != VERSION && name != OUTPUT_ENCODING && name != URL_ESCAPING_CHARSET && name != ERROR && name != NOW) { throw new ParseException("Unknown built-in variable: " + name, this); } } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { if (name == NAMESPACE) { return env.getCurrentNamespace(); } if (name == MAIN) { return env.getMainNamespace(); } if (name == GLOBALS) { return env.getGlobalVariables(); } if (name == LOCALS) { Macro.Context ctx = env.getCurrentMacroContext(); return ctx == null ? null : ctx.getLocals(); } if (name == DATA_MODEL) { return env.getDataModel(); } if (name == VARS) { return new VarsHash(env); } if (name == LOCALE) { return new SimpleScalar(env.getLocale().toString()); } if (name == LANG) { return new SimpleScalar(env.getLocale().getLanguage()); } if (name == CURRENT_NODE || name == NODE) { return env.getCurrentVisitorNode(); } if (name == TEMPLATE_NAME) { return new SimpleScalar(env.getTemplate().getName()); } if (name == PASS) { return Macro.DO_NOTHING_MACRO; } if (name == VERSION) { return new SimpleScalar(Configuration.getVersionNumber()); } if (name == OUTPUT_ENCODING) { String s = env.getOutputEncoding(); return s != null ? new SimpleScalar(s) : null; } if (name == URL_ESCAPING_CHARSET) { String s = env.getURLEscapingCharset(); return s != null ? new SimpleScalar(s) : null; } if (name == ERROR) { return new SimpleScalar(env.getCurrentRecoveredErrorMesssage()); } if (name == NOW) { return new SimpleDate(new Date(), TemplateDateModel.DATETIME); } throw new TemplateException("Invalid built-in variable: " + this, env); } public String toString() { return "." + name; } public String getCanonicalForm() { return "." + name; } boolean isLiteral() { return false; } Expression _deepClone(String name, Expression subst) { return this; } static class VarsHash implements TemplateHashModel { Environment env; VarsHash(Environment env) { this.env = env; } public TemplateModel get(String key) throws TemplateModelException { return env.getVariable(key); } public boolean isEmpty() { return false; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/NumberLiteral.java0000644000175000017500000000704311723544471025114 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * A simple implementation of the TemplateNumberModel * interface. Note that this class is immutable. * @author Jonathan Revusky */ final class NumberLiteral extends Expression implements TemplateNumberModel { private final Number value; public NumberLiteral(Number value) { this.value = value; } TemplateModel _getAsTemplateModel(Environment env) { return new SimpleNumber(value); } public String getStringValue(Environment env) { return env.formatNumber(value); } public Number getAsNumber() { return value; } String getName() { return "the number: '" + value + "'"; } public String getCanonicalForm() { return value.toString(); } boolean isLiteral() { return true; } Expression _deepClone(String name, Expression subst) { return new NumberLiteral(value); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/FMParser.html0000644000175000017500000011674111723544471024057 0ustar ebourgebourg BNF for FMParser

BNF for FMParser

NON-TERMINALS

// Now the actual parsing code, starting

// with the productions for FreeMarker's

// expression syntax.


/**
 * This is the same as OrExpression, since
 * the OR is the operator with the lowest
 * precedence.
 */
Expression ::= OrExpression
/**
 * Lowest level expression, a literal, a variable,
 * or a possibly more complex expression bounded
 * by parentheses.
 */
PrimaryExpression ::= ( NumberLiteral | HashLiteral | StringLiteral | BooleanLiteral | ListLiteral | Identifier | Parenthesis | BuiltinVariable ) ( AddSubExpression )*
Parenthesis ::= <OPEN_PAREN> Expression <CLOSE_PAREN>
/**
 * A primary expression preceded by zero or
 * more unary operators. (The only unary operator we
 * currently have is the NOT.)
 */
UnaryExpression ::= ( UnaryPlusMinusExpression | NotExpression | PrimaryExpression )
NotExpression ::= ( <EXCLAM> )+ PrimaryExpression
UnaryPlusMinusExpression ::= ( <PLUS> | <MINUS> ) PrimaryExpression
AdditiveExpression ::= MultiplicativeExpression ( ( ( <PLUS> | <MINUS> ) ) MultiplicativeExpression )*
/**
 * A unary expression followed by zero or more
 * unary expressions with operators in between.
 */
MultiplicativeExpression ::= UnaryExpression ( ( ( <TIMES> | <DIVIDE> | <PERCENT> ) ) UnaryExpression )*
EqualityExpression ::= RelationalExpression ( ( <NOT_EQUALS> | <EQUALS> | <DOUBLE_EQUALS> ) RelationalExpression )?
RelationalExpression ::= RangeExpression ( ( <NATURAL_GTE> | <ESCAPED_GTE> | <NATURAL_GT> | <ESCAPED_GT> | <LESS_THAN_EQUALS> | <LESS_THAN> ) RangeExpression )?
RangeExpression ::= AdditiveExpression ( <DOT_DOT> ( AdditiveExpression )? )?
AndExpression ::= EqualityExpression ( <AND> EqualityExpression )*
OrExpression ::= AndExpression ( <OR> AndExpression )*
ListLiteral ::= <OPEN_BRACKET> PositionalArgs <CLOSE_BRACKET>
NumberLiteral ::= ( <INTEGER> | <DECIMAL> )
Identifier ::= <ID>
IdentifierOrStringLiteral ::= ( Identifier | StringLiteral )
BuiltinVariable ::= <DOT> <ID>
/**
 * Production that builds up an expression
 * using the dot or dynamic key name
 * or the args list if this is a method invocation.
 */
AddSubExpression ::= ( DotVariable | DynamicKey | MethodArgs | BuiltIn | DefaultTo | Exists )
DefaultTo ::= ( <TERMINATING_EXCLAM> | ( <EXCLAM> ( Expression )? ) )
Exists ::= <EXISTS>
BuiltIn ::= <BUILT_IN> <ID>
/**
 * production for when a key is specified by <DOT> + keyname
 */
DotVariable ::= <DOT> ( <ID> | <TIMES> | <DOUBLE_STAR> | ( <LESS_THAN> | <LESS_THAN_EQUALS> | <ESCAPED_GT> | <ESCAPED_GTE> | <FALSE> | <TRUE> | <IN> | <AS> | <USING> ) )
/**
 * production for when the key is specified
 * in brackets.
 */
DynamicKey ::= <OPEN_BRACKET> Expression <CLOSE_BRACKET>
/**
 * production for an arglist part of a method invocation.
 */
MethodArgs ::= <OPEN_PAREN> PositionalArgs <CLOSE_PAREN>
StringLiteral ::= ( <STRING_LITERAL> | <RAW_STRING> )
BooleanLiteral ::= ( <FALSE> | <TRUE> )
HashLiteral ::= <OPEN_BRACE> ( Expression ( <COMMA> | <COLON> ) Expression ( <COMMA> Expression ( <COMMA> | <COLON> ) Expression )* )? <CLOSE_BRACE>
/**
 * A production representing the ${...}
 * that outputs a variable.
 */
StringOutput ::= <OUTPUT_ESCAPE> Expression <CLOSE_BRACE>
NumericalOutput ::= <NUMERICAL_ESCAPE> Expression ( <SEMICOLON> <ID> )? <CLOSE_BRACE>
If ::= <IF> Expression <DIRECTIVE_END> OptionalBlock ( <ELSE_IF> Expression LooseDirectiveEnd OptionalBlock )* ( <ELSE> OptionalBlock )? <END_IF>
Attempt ::= <ATTEMPT> OptionalBlock Recover ( <END_RECOVER> | <END_ATTEMPT> )
Recover ::= <RECOVER> OptionalBlock
List ::= <LIST> Expression <AS> <ID> <DIRECTIVE_END> OptionalBlock <END_LIST>
ForEach ::= <FOREACH> <ID> <IN> Expression <DIRECTIVE_END> OptionalBlock <END_FOREACH>
Visit ::= <VISIT> Expression ( <USING> Expression )? LooseDirectiveEnd
Recurse ::= ( <SIMPLE_RECURSE> | ( <RECURSE> ( Expression )? ( <USING> Expression )? LooseDirectiveEnd ) )
FallBack ::= <FALLBACK>
/**
 * Production used to break out of a loop or a switch block.
 */
Break ::= <BREAK>
/**
 * Production used to jump out of a macro.
 * The stop instruction terminates the rendering of the template.
 */
Return ::= ( <SIMPLE_RETURN> | <RETURN> Expression LooseDirectiveEnd )
Stop ::= ( <HALT> | <STOP> Expression LooseDirectiveEnd )
Nested ::= ( ( <SIMPLE_NESTED> )| ( <NESTED> PositionalArgs LooseDirectiveEnd ) )
Flush ::= <FLUSH>
Trim ::= ( <TRIM> | <LTRIM> | <RTRIM> | <NOTRIM> )
Assign ::= ( <ASSIGN> | <GLOBALASSIGN> | <LOCALASSIGN> ) IdentifierOrStringLiteral ( ( <EQUALS> Expression ( ( <COMMA> )? IdentifierOrStringLiteral <EQUALS> Expression )* ( <IN> Expression )? LooseDirectiveEnd )| ( ( <IN> Expression )? <DIRECTIVE_END> OptionalBlock ( <END_LOCAL> | <END_ASSIGN> | <END_GLOBAL> ) ) )
Include ::= <INCLUDE> Expression ( <SEMICOLON> )? ( <ID> <EQUALS> Expression )* LooseDirectiveEnd
Import ::= <IMPORT> Expression <AS> <ID> LooseDirectiveEnd
Macro ::= ( <MACRO> | <FUNCTION> ) IdentifierOrStringLiteral ( <OPEN_PAREN> )? ( <ID> ( <ELLIPSIS> )? ( <EQUALS> Expression )? ( <COMMA> )? )* ( <CLOSE_PAREN> )? <DIRECTIVE_END> OptionalBlock ( <END_MACRO> | <END_FUNCTION> )
Compress ::= <COMPRESS> OptionalBlock <END_COMPRESS>
UnifiedMacroTransform ::= <UNIFIED_CALL> Expression ( <TERMINATING_WHITESPACE> )? ( NamedArgs | PositionalArgs ) ( <SEMICOLON> ( ( <TERMINATING_WHITESPACE> )? <ID> ( ( <TERMINATING_WHITESPACE> )? <COMMA> ( <TERMINATING_WHITESPACE> )? <ID> )* )? )? ( <EMPTY_DIRECTIVE_END> | ( <DIRECTIVE_END> OptionalBlock <UNIFIED_CALL_END> ) )
Call ::= <CALL> <ID> ( NamedArgs | ( ( <OPEN_PAREN> )? PositionalArgs ( <CLOSE_PAREN> )? ) ) LooseDirectiveEnd
NamedArgs ::= ( <ID> <EQUALS> Expression )+
PositionalArgs ::= ( Expression ( ( <COMMA> )? Expression )* )?
Comment ::= ( <COMMENT> | <TERSE_COMMENT> ) UnparsedContent
NoParse ::= <NOPARSE> UnparsedContent
Transform ::= <TRANSFORM> Expression ( <SEMICOLON> )? ( <ID> <EQUALS> Expression )* ( <EMPTY_DIRECTIVE_END> | ( <DIRECTIVE_END> OptionalBlock <END_TRANSFORM> ) )
Switch ::= <SWITCH> Expression <DIRECTIVE_END> ( Case )* ( <WHITESPACE> )? <END_SWITCH>
Case ::= ( <WHITESPACE> )? ( <CASE> Expression <DIRECTIVE_END> | <DEFAUL> ) OptionalBlock
Escape ::= <ESCAPE> <ID> <AS> Expression <DIRECTIVE_END> OptionalBlock <END_ESCAPE>
NoEscape ::= <NOESCAPE> OptionalBlock <END_NOESCAPE>
/**
 * Production to terminate potentially empty elements. Either a ">" or "/>"
 */
LooseDirectiveEnd ::= ( <DIRECTIVE_END> | <EMPTY_DIRECTIVE_END> )
Setting ::= <SETTING> <ID> <EQUALS> Expression LooseDirectiveEnd
/**
 * A production for FreeMarker directives.
 */
FreemarkerDirective ::= ( If | List | ForEach | Assign | Include | Import | Macro | Compress | UnifiedMacroTransform | Call | Comment | NoParse | Transform | Switch | Setting | Break | Return | Stop | Flush | Trim | Nested | Escape | NoEscape | Visit | Recurse | FallBack | Attempt )
/**
 * Production for a block of raw text
 * i.e. text that contains no
 * FreeMarker directives.
 */
PCData ::= ( ( <WHITESPACE> | <PRINTABLE_CHARS> | <FALSE_ALERT> ) )+
/**
 * Production for dealing with unparsed content,
 * i.e. what is inside a comment or noparse tag.
 * It returns the ending token. The content
 * of the tag is put in buf.
 */
UnparsedContent ::= ( ( <KEEP_GOING> | <MAYBE_END> | <TERSE_COMMENT_END> | <LONE_LESS_THAN_OR_DASH> ) )+
Content ::= ( ( PCData | StringOutput | NumericalOutput | FreemarkerDirective ) )+
/**
 * A production freemarker text that may contain
 * ${...} and #{...} but no directives.
 */
FreeMarkerText ::= ( ( PCData | StringOutput | NumericalOutput ) )+
/**
 * A production for a block of optional content.
 * Returns an empty Text block if there is no
 * content.
 */
OptionalBlock ::= ( Content )?
HeaderElement ::= ( <WHITESPACE> )? ( <TRIVIAL_FTL_HEADER> | ( <FTL_HEADER> ( <ID> <EQUALS> Expression )* ) LooseDirectiveEnd )
ParamList ::= ( Identifier <EQUALS> Expression ( <COMMA> )? )+
/**
 * Root production to be used when parsing
 * an entire file.
 */
Root ::= ( HeaderElement )? OptionalBlock <EOF>

TOKENS

<DEFAULT> TOKEN : { 
<ATTEMPT: <START_TAG> "attempt" <CLOSE_TAG1>>
|<RECOVER: <START_TAG> "recover" <CLOSE_TAG1>>
|<IF: <START_TAG> "if" <BLANK>>
|<ELSE_IF: <START_TAG> "elseif" <BLANK>>
|<LIST: <START_TAG> "list" <BLANK>>
|<FOREACH: <START_TAG> "foreach" <BLANK>>
|<SWITCH: <START_TAG> "switch" <BLANK>>
|<CASE: <START_TAG> "case" <BLANK>>
|<ASSIGN: <START_TAG> "assign" <BLANK>>
|<GLOBALASSIGN: <START_TAG> "global" <BLANK>>
|<LOCALASSIGN: <START_TAG> "local" <BLANK>>
|<INCLUDE: <START_TAG> "include" <BLANK>>
|<IMPORT: <START_TAG> "import" <BLANK>>
|<FUNCTION: <START_TAG> "function" <BLANK>>
|<MACRO: <START_TAG> "macro" <BLANK>>
|<TRANSFORM: <START_TAG> "transform" <BLANK>>
|<VISIT: <START_TAG> "visit" <BLANK>>
|<STOP: <START_TAG> "stop" <BLANK>>
|<RETURN: <START_TAG> "return" <BLANK>>
|<CALL: <START_TAG> "call" <BLANK>>
|<SETTING: <START_TAG> "setting" <BLANK>>
|<COMPRESS: <START_TAG> "compress" <CLOSE_TAG1>>
|<COMMENT: <START_TAG> "comment" <CLOSE_TAG1>>
|<TERSE_COMMENT: (["<","["]) "#--">
|<NOPARSE: <START_TAG> "noparse" <CLOSE_TAG1>>
|<END_IF: <END_TAG> "if" <CLOSE_TAG1>>
|<END_LIST: <END_TAG> "list" <CLOSE_TAG1>>
|<END_RECOVER: <END_TAG> "recover" <CLOSE_TAG1>>
|<END_ATTEMPT: <END_TAG> "attempt" <CLOSE_TAG1>>
|<END_FOREACH: <END_TAG> "foreach" <CLOSE_TAG1>>
|<END_LOCAL: <END_TAG> "local" <CLOSE_TAG1>>
|<END_GLOBAL: <END_TAG> "global" <CLOSE_TAG1>>
|<END_ASSIGN: <END_TAG> "assign" <CLOSE_TAG1>>
|<END_FUNCTION: <END_TAG> "function" <CLOSE_TAG1>>
|<END_MACRO: <END_TAG> "macro" <CLOSE_TAG1>>
|<END_COMPRESS: <END_TAG> "compress" <CLOSE_TAG1>>
|<END_TRANSFORM: <END_TAG> "transform" <CLOSE_TAG1>>
|<END_SWITCH: <END_TAG> "switch" <CLOSE_TAG1>>
|<ELSE: <START_TAG> "else" <CLOSE_TAG2>>
|<BREAK: <START_TAG> "break" <CLOSE_TAG2>>
|<SIMPLE_RETURN: <START_TAG> "return" <CLOSE_TAG2>>
|<HALT: <START_TAG> "stop" <CLOSE_TAG2>>
|<FLUSH: <START_TAG> "flush" <CLOSE_TAG2>>
|<TRIM: <START_TAG> "t" <CLOSE_TAG2>>
|<LTRIM: <START_TAG> "lt" <CLOSE_TAG2>>
|<RTRIM: <START_TAG> "rt" <CLOSE_TAG2>>
|<NOTRIM: <START_TAG> "nt" <CLOSE_TAG2>>
|<DEFAUL: <START_TAG> "default" <CLOSE_TAG1>>
|<SIMPLE_NESTED: <START_TAG> "nested" <CLOSE_TAG2>>
|<NESTED: <START_TAG> "nested" <BLANK>>
|<SIMPLE_RECURSE: <START_TAG> "recurse" <CLOSE_TAG2>>
|<RECURSE: <START_TAG> "recurse" <BLANK>>
|<FALLBACK: <START_TAG> "fallback" <CLOSE_TAG2>>
|<ESCAPE: <START_TAG> "escape" <BLANK>>
|<END_ESCAPE: <END_TAG> "escape" <CLOSE_TAG1>>
|<NOESCAPE: <START_TAG> "noescape" <CLOSE_TAG1>>
|<END_NOESCAPE: <END_TAG> "noescape" <CLOSE_TAG1>>
|<UNIFIED_CALL: "<@" | "[@">
|<UNIFIED_CALL_END: (["<","["]) "/@" (<ID> ("." <ID>)*)? <CLOSE_TAG1>>
|<FTL_HEADER: ("<#ftl" | "[#ftl") <BLANK>>
|<TRIVIAL_FTL_HEADER: ("<#ftl" | "[#ftl") ("/")? ([">","]"])>
|<UNKNOWN_DIRECTIVE: ("[#" | "[/#" | "<#" | "</#") (["A"-"Z","_","a"-"z"])+>
}

<DEFAULT, NODIRECTIVE> TOKEN : { 
<WHITESPACE: (["\t","\n","\r"," "])+>
|<PRINTABLE_CHARS: (["\u0000"-"\b","\u000b"-"\f","\u000e"-"\u001f","!"-"\"","%"-";","="-"Z","\\"-"z","|"-"\uffff"])+>
|<FALSE_ALERT: ["#","$","<","[","{"]>
|<OUTPUT_ESCAPE: "${">
|<NUMERICAL_ESCAPE: "#{">
}

<FM_EXPRESSION, IN_PAREN, NAMED_PARAMETER_EXPRESSION> SKIP : { 
<(["\t","\n","\r"," "])+>
|<["<","["] ["!","#"] "--">
}

<EXPRESSION_COMMENT> SKIP : { 
<(["\u0000"-",","."-"=","?"-"\\","^"-"\uffff"])+>
|">"
|"]"
|"-"
|<"-->" | "--]">
}

<FM_EXPRESSION, IN_PAREN, NO_SPACE_EXPRESSION, NAMED_PARAMETER_EXPRESSION> TOKEN : { 
<STRING_LITERAL: "\"" (["\u0000"-"!","#"-"[","]"-"\uffff"] | <ESCAPED_CHAR>)* "\"" | "\'" (["\u0000"-"&","("-"[","]"-"\uffff"] | <ESCAPED_CHAR>)* "\'">
|<RAW_STRING: "r" ("\"" (["\u0000"-"!","#"-"\uffff"])* "\"" | "\'" (["\u0000"-"&","("-"\uffff"])* "\'")>
|<FALSE: "false">
|<TRUE: "true">
|<INTEGER: (["0"-"9"])+>
|<DECIMAL: <INTEGER> "." <INTEGER>>
|<DOT: ".">
|<DOT_DOT: "..">
|<BUILT_IN: "?">
|<EXISTS: "??">
|<EQUALS: "=">
|<DOUBLE_EQUALS: "==">
|<NOT_EQUALS: "!=">
|<LESS_THAN: "lt" | "\\lt" | ["<"] | "&lt;">
|<LESS_THAN_EQUALS: "lte" | "\\lte" | "<=" | "&lt;=">
|<ESCAPED_GT: "gt" | "\\gt" | "&gt;">
|<ESCAPED_GTE: "gte" | "\\gte" | "&gt;=">
|<PLUS: "+">
|<MINUS: "-">
|<TIMES: "*">
|<DOUBLE_STAR: "**">
|<ELLIPSIS: "...">
|<DIVIDE: "/">
|<PERCENT: "%">
|<AND: ["&"] | "&&">
|<OR: ["|"] | "||">
|<EXCLAM: "!">
|<COMMA: ",">
|<SEMICOLON: ";">
|<COLON: ":">
|<OPEN_BRACKET: "[">
|<CLOSE_BRACKET: "]">
|<OPEN_PAREN: "(">
|<CLOSE_PAREN: ")">
|<OPEN_BRACE: "{">
|<CLOSE_BRACE: "}">
|<IN: "in">
|<AS: "as">
|<USING: "using">
|<ID: <LETTER> (["$","0"-"9","@"-"Z","_","a"-"z","\u00c0"-"\u00d6","\u00d8"-"\u00f6","\u00f8"-"\u00ff","\u0100"-"\u1fff","\u3040"-"\u318f","\u3300"-"\u337f","\u3400"-"\u3d2d","\u4e00"-"\u9fff","\uf900"-"\ufaff"])*>
|}

<FM_EXPRESSION, NO_SPACE_EXPRESSION, NAMED_PARAMETER_EXPRESSION> TOKEN : { 
<DIRECTIVE_END: ">">
|<EMPTY_DIRECTIVE_END: "/>" | "/]">
}

<IN_PAREN> TOKEN : { 
<NATURAL_GT: ">">
|<NATURAL_GTE: ">=">
}

<NO_SPACE_EXPRESSION> TOKEN : { 
<TERMINATING_WHITESPACE: (["\t","\n","\r"," "])+>
}

<NAMED_PARAMETER_EXPRESSION> TOKEN : { 
<TERMINATING_EXCLAM: "!" (["\t","\n","\r"," "])+>
}

<NO_PARSE> TOKEN : { 
<TERSE_COMMENT_END: "-->" | "--]">
|<MAYBE_END: (["<","["]) "/" ("#")? (["A"-"Z","a"-"z"])+ (["\t","\n","\r"," "])* ([">","]"])>
|<KEEP_GOING: (["\u0000"-",","."-";","="-"Z","\\"-"\uffff"])+>
|<LONE_LESS_THAN_OR_DASH: ["-","<","["]>
}

libfreemarker-java-2.3.19.orig/src/freemarker/core/FallbackInstruction.java0000644000175000017500000000571311723544471026312 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.TemplateException; final class FallbackInstruction extends TemplateElement { void accept(Environment env) throws IOException, TemplateException { env.fallback(); } public String getCanonicalForm() { return "<#fallback/>"; } public String getDescription() { return "fallback instruction"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BooleanLiteral.java0000644000175000017500000000662411723544467025254 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; final class BooleanLiteral extends Expression { private final boolean val; public BooleanLiteral(boolean val) { this.val = val; } static TemplateBooleanModel getTemplateModel(boolean b) { return b? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } boolean isTrue(Environment env) { return val; } public String getCanonicalForm() { return val ? "true" : "false"; } public String toString() { return val ? "true" : "false"; } TemplateModel _getAsTemplateModel(Environment env) { return val ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } boolean isLiteral() { return true; } Expression _deepClone(String name, Expression subst) { return new BooleanLiteral(val); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/DebugBreak.java0000644000175000017500000000704011723544472024340 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.debug.impl.DebuggerService; import freemarker.template.TemplateException; /** * @author Attila Szegedi * @version $Id: DebugBreak.java,v 1.2 2004/09/11 13:11:14 stephanmueller Exp $ */ public class DebugBreak extends TemplateElement { public DebugBreak(TemplateElement nestedBlock) { this.nestedBlock = nestedBlock; nestedBlock.parent = this; copyLocationFrom(nestedBlock); } protected void accept(Environment env) throws TemplateException, IOException { if(!DebuggerService.suspendEnvironment(env, nestedBlock.getBeginLine())) { nestedBlock.accept(env); } else { throw new StopException(env, "Stopped by debugger"); } } public String getDescription() { return nestedBlock.getDescription(); } public String getCanonicalForm() { return nestedBlock.getCanonicalForm(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Assignment.java0000644000175000017500000001420311723544471024453 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * An instruction that assigns a literal or reference, to a single-identifier * variable. */ final class Assignment extends TemplateElement { private String variableName; private Expression value, namespaceExp; private int scope; static final int NAMESPACE = 1; static final int LOCAL = 2; static final int GLOBAL = 3; /** * @param variableName the variable name to assign to. * @param value the expression to assign. * @param scope the scope of the assignment, one of NAMESPACE, LOCAL, or GLOBAL */ Assignment(String variableName, Expression value, int scope) { this.variableName = variableName; this.value = value; this.scope = scope; } void setNamespaceExp(Expression namespaceExp) { this.namespaceExp = namespaceExp; } void accept(Environment env) throws TemplateException { TemplateModel tm = value.getAsTemplateModel(env); Environment.Namespace namespace = null; if (namespaceExp != null) { boolean oops = false; try { namespace = (Environment.Namespace) namespaceExp.getAsTemplateModel(env); } catch (ClassCastException cce) { oops = true; } if (oops || namespace==null) { throw new InvalidReferenceException(getStartLocation() + "\nInvalid reference to namespace: " + namespaceExp, env); } } if (tm == null) { if (env.isClassicCompatible()) { tm = TemplateScalarModel.EMPTY_STRING; } else { String msg = "Error " + getStartLocation() +"\n" + value + " is undefined." +"\nIt cannot be assigned to " + variableName; throw new InvalidReferenceException(msg, env); } } if (scope == LOCAL) { env.setLocalVariable(variableName, tm); } else { if (namespace == null) { if (scope == GLOBAL) { namespace = env.getGlobalNamespace(); } else if (scope == NAMESPACE) { namespace = env.getCurrentNamespace(); } } namespace.put(variableName, tm); } } public String getCanonicalForm() { StringBuffer buf = new StringBuffer(); if (!(parent instanceof AssignmentInstruction)) { if (scope == LOCAL) { buf.append("<#local "); } else if (scope ==GLOBAL) { buf.append("<#global "); } else { buf.append("<#assign "); } } buf.append (variableName); buf.append('='); buf.append(value.getCanonicalForm()); if (!(parent instanceof AssignmentInstruction)) { if (namespaceExp != null) { buf.append(" in "); buf.append(namespaceExp.getCanonicalForm()); } buf.append(">"); } return buf.toString(); } public String getDescription() { String s =""; if (!(parent instanceof AssignmentInstruction)) { s = "assignment: "; if (scope == LOCAL) { s = "local " + s; } else if (scope == GLOBAL) { s = "global " + s; } } return s + variableName + "=" + value; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BlockAssignment.java0000644000175000017500000001514311723544467025437 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.Map; import freemarker.template.SimpleScalar; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateTransformModel; /** * @version $Id: BlockAssignment.java,v 1.4 2004/07/07 21:11:12 szegedia Exp $ */ final class BlockAssignment extends TemplateElement { private final String varName; private final Expression namespaceExp; private final int scope; BlockAssignment(TemplateElement nestedBlock, String varName, int scope, Expression namespaceExp) { this.nestedBlock = nestedBlock; this.varName = varName; this.namespaceExp = namespaceExp; this.scope = scope; } void accept(Environment env) throws TemplateException, IOException { if (nestedBlock != null) { env.visit(nestedBlock, new CaptureOutput(env), null); } else { TemplateModel value = new SimpleScalar(""); if (namespaceExp != null) { Environment.Namespace ns = (Environment.Namespace) namespaceExp.getAsTemplateModel(env); ns.put(varName, value); } else if (scope == Assignment.NAMESPACE) { env.setVariable(varName, value); } else if (scope == Assignment.GLOBAL) { env.setGlobalVariable(varName, value); } else if (scope == Assignment.LOCAL) { env.setLocalVariable(varName, value); } } } private class CaptureOutput implements TemplateTransformModel { private final Environment env; private final Environment.Namespace fnsModel; CaptureOutput(Environment env) throws TemplateException { this.env = env; TemplateModel nsModel = null; if(namespaceExp != null) { nsModel = namespaceExp.getAsTemplateModel(env); if (!(nsModel instanceof Environment.Namespace)) { throw new TemplateException( "namespace parameter does not specify " + "a namespace. It is a " + nsModel.getClass().getName(), env); } } fnsModel = (Environment.Namespace )nsModel; } public Writer getWriter(Writer out, Map args) { return new StringWriter() { public void close() { SimpleScalar result = new SimpleScalar(toString()); switch(scope) { case Assignment.NAMESPACE: { if(fnsModel != null) { fnsModel.put(varName, result); } else { env.setVariable(varName, result); } break; } case Assignment.LOCAL: { env.setLocalVariable(varName, result); break; } case Assignment.GLOBAL: { env.setGlobalVariable(varName, result); break; } } } }; } } public String getCanonicalForm() { String key; switch(scope) { case Assignment.LOCAL: { key = "local"; break; } case Assignment.GLOBAL: { key = "global"; break; } default: { key = "assign"; break; } } String block = nestedBlock == null ? "" : nestedBlock.getCanonicalForm(); return "<#" + key + " " + varName + (namespaceExp != null ? " in " + namespaceExp.getCanonicalForm() : "") + ">" +block + ""; } public String getDescription() { return "block assignment to variable: " + varName; } boolean isIgnorable() { return false; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/CommandLine.java0000644000175000017500000000707111723544470024535 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; /** * FreeMarker command-line utility, the Main-Class of freemarker.jar. * Currently it just prints the version number. * * @version $Id: CommandLine.java,v 1.2 2003/09/24 12:15:08 ddekany Exp $ */ public class CommandLine { public static void main(String[] args) { System.out.println(); System.out.print("FreeMarker version "); System.out.println(Configuration.getVersionNumber()); System.out.println(); System.out.println("Copyright (c) 2003 The Visigoth Software Society."); System.out.println("All rights reserved."); System.out.println(); System.out.println("This is Free software. Please read the LICENSE.txt comes with "); System.out.println("the distribution for more details."); System.out.println(); System.out.println("For more information and for updates visit our WWW site:"); System.out.println("http://freemarker.org/"); System.out.println(); } }libfreemarker-java-2.3.19.orig/src/freemarker/core/EscapeBlock.java0000644000175000017500000000761511723544472024530 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.*; /** * Representation of the compile-time Escape directive. * @version $Id: EscapeBlock.java,v 1.1 2003/04/22 21:05:01 revusky Exp $ * @author Attila Szegedi */ class EscapeBlock extends TemplateElement { private final String variable; private final Expression expr; private Expression escapedExpr; EscapeBlock(String variable, Expression expr, Expression escapedExpr) { this.variable = variable; this.expr = expr; this.escapedExpr = escapedExpr; } void setContent(TemplateElement nestedBlock) { this.nestedBlock = nestedBlock; // We don't need it anymore at this point this.escapedExpr = null; } void accept(Environment env) throws TemplateException, IOException { if (nestedBlock != null) { env.visit(nestedBlock); } } Expression doEscape(Expression subst) { return escapedExpr.deepClone(variable, subst); } public String getDescription() { return "escape " + variable + " as " + expr.toString(); } public String getCanonicalForm() { return "<#escape " + variable + " as " + expr.getCanonicalForm() + ">" + nestedBlock.getCanonicalForm() + ""; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BodyInstruction.java0000644000175000017500000001357111723544470025510 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * An instruction that processes the nested block within a macro instruction. * @author Jonathan Revusky */ final class BodyInstruction extends TemplateElement { private List bodyParameters; BodyInstruction(List bodyParameters) { this.bodyParameters = bodyParameters; } List getBodyParameters() { return bodyParameters; } /** * There is actually a subtle but essential point in the code below. * A macro operates in the context in which it is defined. However, * a nested block within a macro instruction is defined in the * context in which the macro was invoked. So, we actually need to * temporarily switch the namespace and macro context back to * what it was before macro invocation to implement this properly. * I (JR) realized this thanks to some incisive comments from Daniel Dekany. */ void accept(Environment env) throws IOException, TemplateException { Context bodyContext = new Context(env); env.visit(bodyContext); } public String getCanonicalForm() { StringBuffer buf = new StringBuffer("<#nested"); if (bodyParameters != null) { for (int i = 0; i'); return buf.toString(); } public String getDescription() { return "nested macro content"; } /* boolean heedsOpeningWhitespace() { return true; } boolean heedsTrailingWhitespace() { return true; } */ class Context implements LocalContext { Macro.Context invokingMacroContext; Environment.Namespace bodyVars; Context(Environment env) throws TemplateException { invokingMacroContext = env.getCurrentMacroContext(); List bodyParameterNames = invokingMacroContext.bodyParameterNames; if (bodyParameters != null) { for (int i=0; i"; } return "<#visit " + targetNode.getCanonicalForm() + " using " + namespaces.getCanonicalForm() + "/>"; } public String getDescription() { return "visit instruction"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/RecurseNode.java0000644000175000017500000001100211723544470024552 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.io.IOException; import freemarker.template.*; /** * An instruction to visit the children of a node. */ final class RecurseNode extends TemplateElement { Expression targetNode, namespaces; RecurseNode(Expression targetNode, Expression namespaces) { this.targetNode = targetNode; this.namespaces = namespaces; } void accept(Environment env) throws IOException, TemplateException { TemplateModel node = targetNode == null ? null : targetNode.getAsTemplateModel(env); TemplateModel nss = namespaces == null ? null : namespaces.getAsTemplateModel(env); if (namespaces instanceof StringLiteral) { nss = env.importLib(((TemplateScalarModel) nss).getAsString(), null); } else if (namespaces instanceof ListLiteral) { nss = ((ListLiteral) namespaces).evaluateStringsToNamespaces(env); } if (node != null && !(node instanceof TemplateNodeModel)) { throw new TemplateException("Expecting an XML node here, for expression: " + targetNode + ", found a: " + node.getClass().getName(), env); } if (nss != null) { if (nss instanceof TemplateHashModel) { SimpleSequence ss = new SimpleSequence(1); ss.add(nss); nss = ss; } else if (!(nss instanceof TemplateSequenceModel)) { throw new TemplateException("Expecting a sequence of namespaces after 'using'", env); } } env.recurse((TemplateNodeModel) node, (TemplateSequenceModel) nss); } public String getCanonicalForm() { String result = "<#recurse"; if (targetNode != null) result += (" " + targetNode.getCanonicalForm()); if (namespaces != null) result += (" using " + namespaces.getCanonicalForm()); return result + "/>"; } public String getDescription() { return "recurse instruction"; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/Dot.java0000644000175000017500000000742511723544470023100 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.TemplateException; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; /** * The dot operator. Used to reference items inside a * TemplateHashModel. */ final class Dot extends Expression { private final Expression target; private final String key; Dot(Expression target, String key) { this.target = target; this.key = key; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel leftModel = target.getAsTemplateModel(env); if(leftModel instanceof TemplateHashModel) { return ((TemplateHashModel) leftModel).get(key); } throw invalidTypeException(leftModel, target, env, "hash"); } public String getCanonicalForm() { return target.getCanonicalForm() + "." + key; } boolean isLiteral() { return target.isLiteral(); } Expression _deepClone(String name, Expression subst) { return new Dot(target.deepClone(name, subst), key); } boolean onlyHasIdentifiers() { return (target instanceof Identifier) || ((target instanceof Dot) && ((Dot) target).onlyHasIdentifiers()); } }libfreemarker-java-2.3.19.orig/src/freemarker/core/CollectionAndSequence.java0000644000175000017500000001140511723544470026552 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import java.util.*; import java.io.Serializable; /** * Add sequence capabilities to an existing collection, or * vice versa. Used by ?keys and ?values built-ins. */ final public class CollectionAndSequence implements TemplateCollectionModel, TemplateSequenceModel, Serializable { private TemplateCollectionModel collection; private TemplateSequenceModel sequence; private ArrayList data; public CollectionAndSequence(TemplateCollectionModel collection) { this.collection = collection; } public CollectionAndSequence(TemplateSequenceModel sequence) { this.sequence = sequence; } public TemplateModelIterator iterator() throws TemplateModelException { if (collection != null) { return collection.iterator(); } else { return new SequenceIterator(sequence); } } public TemplateModel get(int i) throws TemplateModelException { if (sequence != null) { return sequence.get(i); } else { initSequence(); return (TemplateModel)data.get(i); } } public int size() throws TemplateModelException { if (sequence != null) { return sequence.size(); } else { initSequence(); return data.size(); } } private void initSequence() throws TemplateModelException { if (data == null) { data = new ArrayList(); TemplateModelIterator it = collection.iterator(); while (it.hasNext()) { data.add(it.next()); } } } private static class SequenceIterator implements TemplateModelIterator { private final TemplateSequenceModel sequence; private final int size; private int index = 0; SequenceIterator(TemplateSequenceModel sequence) throws TemplateModelException { this.sequence = sequence; this.size = sequence.size(); } public TemplateModel next() throws TemplateModelException { return sequence.get(index++); } public boolean hasNext() { return index < size; } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/TrimInstruction.java0000644000175000017500000000717111723544470025525 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; /** * An instruction that indicates that that opening * and trailing whitespace on this line should be trimmed. * @version $Id: TrimInstruction.java,v 1.2 2003/08/29 09:42:38 revusky Exp $ */ final class TrimInstruction extends TemplateElement { final boolean left, right; TrimInstruction(boolean left, boolean right) { this.left = left; this.right = right; } void accept(Environment env) { // This instruction does nothing at render-time, only parse-time. } public String getCanonicalForm() { if (left && right) { return "<#t>"; } else if (left) { return "<#lt>"; } else if (right) { return "<#rt>"; } else { return "<#nt>"; } } public String getDescription() { String type = ""; if (!right) type = "left "; if (!left) type = "right "; if (!left && !right) type = "no-"; return type + "trim instruction"; } boolean isIgnorable() { return true; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/SimpleCharStream.java0000644000175000017500000002350611723544467025561 0ustar ebourgebourg/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 3.0 */ package freemarker.core; /** * An implementation of interface CharStream, where the stream is assumed to * contain only ASCII characters (without unicode processing). */ public class SimpleCharStream { public static final boolean staticFlag = false; int bufsize; int available; int tokenBegin; public int bufpos = -1; protected int bufline[]; protected int bufcolumn[]; protected int column = 0; protected int line = 1; protected boolean prevCharIsCR = false; protected boolean prevCharIsLF = false; protected java.io.Reader inputStream; protected char[] buffer; protected int maxNextCharInd = 0; protected int inBuf = 0; protected void ExpandBuff(boolean wrapAround) { char[] newbuffer = new char[bufsize + 2048]; int newbufline[] = new int[bufsize + 2048]; int newbufcolumn[] = new int[bufsize + 2048]; try { if (wrapAround) { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos); buffer = newbuffer; System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); bufline = newbufline; System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); bufcolumn = newbufcolumn; maxNextCharInd = (bufpos += (bufsize - tokenBegin)); } else { System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); buffer = newbuffer; System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); bufline = newbufline; System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); bufcolumn = newbufcolumn; maxNextCharInd = (bufpos -= tokenBegin); } } catch (Throwable t) { throw new Error(t.getMessage()); } bufsize += 2048; available = bufsize; tokenBegin = 0; } protected void FillBuff() throws java.io.IOException { if (maxNextCharInd == available) { if (available == bufsize) { if (tokenBegin > 2048) { bufpos = maxNextCharInd = 0; available = tokenBegin; } else if (tokenBegin < 0) bufpos = maxNextCharInd = 0; else ExpandBuff(false); } else if (available > tokenBegin) available = bufsize; else if ((tokenBegin - available) < 2048) ExpandBuff(true); else available = tokenBegin; } int i; try { if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) { inputStream.close(); throw new java.io.IOException(); } else maxNextCharInd += i; return; } catch(java.io.IOException e) { --bufpos; backup(0); if (tokenBegin == -1) tokenBegin = bufpos; throw e; } } public char BeginToken() throws java.io.IOException { tokenBegin = -1; char c = readChar(); tokenBegin = bufpos; return c; } protected void UpdateLineColumn(char c) { column++; if (prevCharIsLF) { prevCharIsLF = false; line += (column = 1); } else if (prevCharIsCR) { prevCharIsCR = false; if (c == '\n') { prevCharIsLF = true; } else line += (column = 1); } switch (c) { case '\r' : prevCharIsCR = true; break; case '\n' : prevCharIsLF = true; break; case '\t' : column--; column += (8 - (column & 07)); break; default : break; } bufline[bufpos] = line; bufcolumn[bufpos] = column; } public char readChar() throws java.io.IOException { if (inBuf > 0) { --inBuf; if (++bufpos == bufsize) bufpos = 0; return buffer[bufpos]; } if (++bufpos >= maxNextCharInd) FillBuff(); char c = buffer[bufpos]; UpdateLineColumn(c); return (c); } /** * @deprecated * @see #getEndColumn */ public int getColumn() { return bufcolumn[bufpos]; } /** * @deprecated * @see #getEndLine */ public int getLine() { return bufline[bufpos]; } public int getEndColumn() { return bufcolumn[bufpos]; } public int getEndLine() { return bufline[bufpos]; } public int getBeginColumn() { return bufcolumn[tokenBegin]; } public int getBeginLine() { return bufline[tokenBegin]; } public void backup(int amount) { inBuf += amount; if ((bufpos -= amount) < 0) bufpos += bufsize; } public SimpleCharStream(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; line = startline; column = startcolumn - 1; available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; } public SimpleCharStream(java.io.Reader dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } public SimpleCharStream(java.io.Reader dstream) { this(dstream, 1, 1, 4096); } public void ReInit(java.io.Reader dstream, int startline, int startcolumn, int buffersize) { inputStream = dstream; line = startline; column = startcolumn - 1; if (buffer == null || buffersize != buffer.length) { available = bufsize = buffersize; buffer = new char[buffersize]; bufline = new int[buffersize]; bufcolumn = new int[buffersize]; } prevCharIsLF = prevCharIsCR = false; tokenBegin = inBuf = maxNextCharInd = 0; bufpos = -1; } public void ReInit(java.io.Reader dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } public void ReInit(java.io.Reader dstream) { ReInit(dstream, 1, 1, 4096); } public SimpleCharStream(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); } public SimpleCharStream(java.io.InputStream dstream, int startline, int startcolumn) { this(dstream, startline, startcolumn, 4096); } public SimpleCharStream(java.io.InputStream dstream) { this(dstream, 1, 1, 4096); } public void ReInit(java.io.InputStream dstream, int startline, int startcolumn, int buffersize) { ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); } public void ReInit(java.io.InputStream dstream) { ReInit(dstream, 1, 1, 4096); } public void ReInit(java.io.InputStream dstream, int startline, int startcolumn) { ReInit(dstream, startline, startcolumn, 4096); } public String GetImage() { if (bufpos >= tokenBegin) return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); else return new String(buffer, tokenBegin, bufsize - tokenBegin) + new String(buffer, 0, bufpos + 1); } public char[] GetSuffix(int len) { char[] ret = new char[len]; if ((bufpos + 1) >= len) System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); else { System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, len - bufpos - 1); System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); } return ret; } public void Done() { buffer = null; bufline = null; bufcolumn = null; } /** * Method to adjust line and column numbers for the start of a token. */ public void adjustBeginLineColumn(int newLine, int newCol) { int start = tokenBegin; int len; if (bufpos >= tokenBegin) { len = bufpos - tokenBegin + inBuf + 1; } else { len = bufsize - tokenBegin + bufpos + 1 + inBuf; } int i = 0, j = 0, k = 0; int nextColDiff = 0, columnDiff = 0; while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) { bufline[j] = newLine; nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; bufcolumn[j] = newCol + columnDiff; columnDiff = nextColDiff; i++; } if (i < len) { bufline[j] = newLine++; bufcolumn[j] = newCol + columnDiff; while (i++ < len) { if (bufline[j = start % bufsize] != bufline[++start % bufsize]) bufline[j] = newLine++; else bufline[j] = newLine; } } line = bufline[j]; column = bufcolumn[j]; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/BuiltIn.java0000644000175000017500000016037311723544471023723 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import java.io.UnsupportedEncodingException; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.DateUtil; import freemarker.template.utility.StringUtil; import freemarker.core.NodeBuiltins.*; import freemarker.core.NumericalBuiltins.*; import freemarker.core.SequenceBuiltins.*; import freemarker.core.StringBuiltins.*; import freemarker.core.DateBuiltins.*; /** * The ? operator used to get the * functionality of built-in unary operators * @author Jonathan Revusky */ abstract class BuiltIn extends Expression implements Cloneable { Expression target; String key; static final HashMap builtins = new HashMap(); static { // These are the only ones we have now. // We throw a parse exception if it's not one of these. builtins.put("ancestors", new ancestorsBI()); builtins.put("byte", new byteBI()); builtins.put("c", new cBI()); builtins.put("cap_first", new cap_firstBI()); builtins.put("capitalize", new capitalizeBI()); builtins.put("ceiling", new ceilingBI()); builtins.put("children", new childrenBI()); builtins.put("chop_linebreak", new chop_linebreakBI()); builtins.put("contains", new containsBI()); builtins.put("date", new dateBI(TemplateDateModel.DATE)); builtins.put("datetime", new dateBI(TemplateDateModel.DATETIME)); builtins.put("default", new defaultBI()); builtins.put("double", new doubleBI()); builtins.put("ends_with", new ends_withBI()); builtins.put("eval", new evalBI()); builtins.put("exists", new existsBI()); builtins.put("first", new firstBI()); builtins.put("float", new floatBI()); builtins.put("floor", new floorBI()); builtins.put("chunk", new chunkBI()); builtins.put("has_content", new has_contentBI()); builtins.put("html", new htmlBI()); builtins.put("if_exists", new if_existsBI()); builtins.put("index_of", new index_ofBI()); builtins.put("int", new intBI()); builtins.put("interpret", new Interpret()); builtins.put("is_boolean", new is_booleanBI()); builtins.put("is_collection", new is_collectionBI()); builtins.put("is_date", new is_dateBI()); builtins.put("is_directive", new is_directiveBI()); builtins.put("is_enumerable", new is_enumerableBI()); builtins.put("is_hash_ex", new is_hash_exBI()); builtins.put("is_hash", new is_hashBI()); builtins.put("is_indexable", new is_indexableBI()); builtins.put("is_macro", new is_macroBI()); builtins.put("is_method", new is_methodBI()); builtins.put("is_node", new is_nodeBI()); builtins.put("is_number", new is_numberBI()); builtins.put("is_sequence", new is_sequenceBI()); builtins.put("is_string", new is_stringBI()); builtins.put("is_transform", new is_transformBI()); builtins.put("iso_utc", new iso_tz_BI("iso_utc", /* showOffset = */ true, DateUtil.ACCURACY_SECONDS, /* useUTC = */ true)); builtins.put("iso_utc_nz", new iso_tz_BI("iso_utc_nz", /* showOffset = */ false, DateUtil.ACCURACY_SECONDS, /* useUTC = */ true)); builtins.put("iso_utc_ms", new iso_tz_BI("iso_utc_ms", /* showOffset = */ true, DateUtil.ACCURACY_MILLISECONDS, /* useUTC = */ true)); builtins.put("iso_utc_ms_nz", new iso_tz_BI("iso_utc_ms_nz", /* showOffset = */ false, DateUtil.ACCURACY_MILLISECONDS, /* useUTC = */ true)); builtins.put("iso_utc_m", new iso_tz_BI("iso_utc_m", /* showOffset = */ true, DateUtil.ACCURACY_MINUTES, /* useUTC = */ true)); builtins.put("iso_utc_m_nz", new iso_tz_BI("iso_utc_m_nz", /* showOffset = */ false, DateUtil.ACCURACY_MINUTES, /* useUTC = */ true)); builtins.put("iso_utc_h", new iso_tz_BI("iso_utc_h", /* showOffset = */ true, DateUtil.ACCURACY_HOURS, /* useUTC = */ true)); builtins.put("iso_utc_h_nz", new iso_tz_BI("iso_utc_h_nz", /* showOffset = */ false, DateUtil.ACCURACY_HOURS, /* useUTC = */ true)); builtins.put("iso_local", new iso_tz_BI("iso_local", /* showOffset = */ true, DateUtil.ACCURACY_SECONDS, /* useUTC = */ false)); builtins.put("iso_local_nz", new iso_tz_BI("iso_local_nz", /* showOffset = */ false, DateUtil.ACCURACY_SECONDS, /* useUTC = */ false)); builtins.put("iso_local_ms", new iso_tz_BI("iso_local_ms", /* showOffset = */ true, DateUtil.ACCURACY_MILLISECONDS, /* useUTC = */ false)); builtins.put("iso_local_ms_nz", new iso_tz_BI("iso_local_ms_nz", /* showOffset = */ false, DateUtil.ACCURACY_MILLISECONDS, /* useUTC = */ false)); builtins.put("iso_local_m", new iso_tz_BI("iso_local_m", /* showOffset = */ true, DateUtil.ACCURACY_MINUTES, /* useUTC = */ false)); builtins.put("iso_local_m_nz", new iso_tz_BI("iso_local_m_nz", /* showOffset = */ false, DateUtil.ACCURACY_MINUTES, /* useUTC = */ false)); builtins.put("iso_local_h", new iso_tz_BI("iso_local_h", /* showOffset = */ true, DateUtil.ACCURACY_HOURS, /* useUTC = */ false)); builtins.put("iso_local_h_nz", new iso_tz_BI("iso_local_h_nz", /* showOffset = */ false, DateUtil.ACCURACY_HOURS, /* useUTC = */ false)); builtins.put("iso", new iso_BI("iso", /* showOffset = */ true, DateUtil.ACCURACY_SECONDS)); builtins.put("iso_nz", new iso_BI("iso_nz", /* showOffset = */ false, DateUtil.ACCURACY_SECONDS)); builtins.put("iso_ms", new iso_BI("iso_ms", /* showOffset = */ true, DateUtil.ACCURACY_MILLISECONDS)); builtins.put("iso_ms_nz", new iso_BI("iso_ms_nz", /* showOffset = */ false, DateUtil.ACCURACY_MILLISECONDS)); builtins.put("iso_m", new iso_BI("iso_m", /* showOffset = */ true, DateUtil.ACCURACY_MINUTES)); builtins.put("iso_m_nz", new iso_BI("iso_m_nz", /* showOffset = */ false, DateUtil.ACCURACY_MINUTES)); builtins.put("iso_h", new iso_BI("iso_h", /* showOffset = */ true, DateUtil.ACCURACY_HOURS)); builtins.put("iso_h_nz", new iso_BI("iso_h_nz", /* showOffset = */ false, DateUtil.ACCURACY_HOURS)); builtins.put("j_string", new j_stringBI()); builtins.put("js_string", new js_stringBI()); builtins.put("json_string", new json_stringBI()); builtins.put("keys", new keysBI()); builtins.put("last_index_of", new last_index_ofBI()); builtins.put("last", new lastBI()); builtins.put("left_pad", new left_padBI()); builtins.put("length", new lengthBI()); builtins.put("long", new longBI()); builtins.put("lower_case", new lower_caseBI()); builtins.put("namespace", new namespaceBI()); builtins.put("new", new NewBI()); builtins.put("node_name", new node_nameBI()); builtins.put("node_namespace", new node_namespaceBI()); builtins.put("node_type", new node_typeBI()); builtins.put("number", new numberBI()); builtins.put("number_to_date", new number_to_dateBI(TemplateDateModel.DATE)); builtins.put("number_to_time", new number_to_dateBI(TemplateDateModel.TIME)); builtins.put("number_to_datetime", new number_to_dateBI(TemplateDateModel.DATETIME)); builtins.put("parent", new parentBI()); builtins.put("replace", new replaceBI()); builtins.put("reverse", new reverseBI()); builtins.put("right_pad", new right_padBI()); builtins.put("root", new rootBI()); builtins.put("round", new roundBI()); builtins.put("rtf", new rtfBI()); builtins.put("seq_contains", new seq_containsBI()); builtins.put("seq_index_of", new seq_index_ofBI(1)); builtins.put("seq_last_index_of", new seq_index_ofBI(-1)); builtins.put("short", new shortBI()); builtins.put("size", new sizeBI()); builtins.put("sort_by", new sort_byBI()); builtins.put("sort", new sortBI()); builtins.put("split", new splitBI()); builtins.put("starts_with", new starts_withBI()); builtins.put("string", new stringBI()); builtins.put("substring", new substringBI()); builtins.put("time", new dateBI(TemplateDateModel.TIME)); builtins.put("trim", new trimBI()); builtins.put("uncap_first", new uncap_firstBI()); builtins.put("upper_case", new upper_caseBI()); builtins.put("url", new urlBI()); builtins.put("values", new valuesBI()); builtins.put("web_safe", builtins.get("html")); // deprecated; use ?html instead builtins.put("word_list", new word_listBI()); builtins.put("xhtml", new xhtmlBI()); builtins.put("xml", new xmlBI()); try { Class.forName("java.util.regex.Pattern"); builtins.put("matches", instantiate("freemarker.core.RegexBuiltins$matchesBI")); builtins.put("groups", instantiate("freemarker.core.RegexBuiltins$groupsBI")); builtins.put("replace", instantiate("freemarker.core.RegexBuiltins$replace_reBI")); builtins.put("split", instantiate("freemarker.core.RegexBuiltins$split_reBI")); } catch (Exception e) {} } private static Object instantiate(String className) throws Exception { return ClassUtil.forName(className).newInstance(); } static BuiltIn newBuiltIn(Expression target, String key, Token tok, String templateName) throws ParseException { BuiltIn bi = (BuiltIn) builtins.get(key); if (bi == null) { String locationInfo = "Error on line " + tok.beginLine + ", column " + tok.beginColumn + ", in template " + templateName + "\n"; StringBuffer buf = new StringBuffer("Found " + key + ", expecting one of: "); for (Iterator it= builtins.keySet().iterator(); it.hasNext();) { if (it.hasNext()) { buf.append(" "); } else { buf.append( " or "); } buf.append(it.next()); if (it.hasNext()) { buf.append(", "); } } throw new ParseException(locationInfo + buf, target); } try { bi = (BuiltIn) bi.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } bi.target = target; bi.key = key; return bi; } public String getCanonicalForm() { return target.getCanonicalForm() + "?" + key; } boolean isLiteral() { return false; // be on the safe side. } Expression _deepClone(String name, Expression subst) { try { BuiltIn clone = (BuiltIn)clone(); clone.target = target.deepClone(name, subst); return clone; } catch (CloneNotSupportedException e) { throw new InternalError(); } } static class lengthBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return new SimpleNumber(target.getStringValue(env).length()); } } static class dateBI extends BuiltIn { private final int dateType; dateBI(int dateType) { this.dateType = dateType; } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateDateModel) { TemplateDateModel dmodel = (TemplateDateModel)model; int dtype = dmodel.getDateType(); // Any date model can be coerced into its own type if(dateType == dtype) { return model; } // unknown and datetime can be coerced into any date type if(dtype == TemplateDateModel.UNKNOWN || dtype == TemplateDateModel.DATETIME) { return new SimpleDate(dmodel.getAsDate(), dateType); } throw new TemplateException( "Cannot convert " + TemplateDateModel.TYPE_NAMES.get(dtype) + " into " + TemplateDateModel.TYPE_NAMES.get(dateType), env); } // Otherwise, interpret as a string and attempt // to parse it into a date. String s = target.getStringValue(env); return new DateParser(s, env); } private class DateParser implements TemplateDateModel, TemplateMethodModel, TemplateHashModel { private final String text; private final Environment env; private final DateFormat defaultFormat; private Date cachedValue; DateParser(String text, Environment env) throws TemplateModelException { this.text = text; this.env = env; this.defaultFormat = env.getDateFormatObject(dateType); } public Date getAsDate() throws TemplateModelException { if(cachedValue == null) { cachedValue = parse(defaultFormat); } return cachedValue; } public int getDateType() { return dateType; } public TemplateModel get(String pattern) throws TemplateModelException { return new SimpleDate( parse(env.getDateFormatObject(dateType, pattern)), dateType); } public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 1) { throw new TemplateModelException( "string?" + key + "(...) requires exactly 1 argument."); } return get((String) arguments.get(0)); } public boolean isEmpty() { return false; } private Date parse(DateFormat df) throws TemplateModelException { try { return df.parse(text); } catch(java.text.ParseException e) { String pattern = null; if (df instanceof SimpleDateFormat) { pattern = ((SimpleDateFormat) df).toPattern(); } String mess = "Error: " + getStartLocation() + "\nThe string doesn't match the expected date/time format. " + "The string to parse was: " + StringUtil.jQuote(text) + (pattern != null ? ". The expected format was: " + StringUtil.jQuote(pattern) + "." : ""); throw new TemplateModelException(mess, e); } } } } static class stringBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateNumberModel) { return new NumberFormatter(EvaluationUtil.getNumber((TemplateNumberModel)model, target, env), env); } if (model instanceof TemplateDateModel) { TemplateDateModel dm = (TemplateDateModel)model; int dateType = dm.getDateType(); return new DateFormatter(EvaluationUtil.getDate(dm, target, env), dateType, env); } if (model instanceof SimpleScalar) { return model; } if (model instanceof TemplateBooleanModel) { return new BooleanFormatter((TemplateBooleanModel) model, env); } if (model instanceof TemplateScalarModel) { return new SimpleScalar(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "number, date, or string"); } private static class NumberFormatter implements TemplateScalarModel, TemplateHashModel, TemplateMethodModel { private final Number number; private final Environment env; private final NumberFormat defaultFormat; private String cachedValue; NumberFormatter(Number number, Environment env) { this.number = number; this.env = env; defaultFormat = env.getNumberFormatObject(env.getNumberFormat()); } public String getAsString() { if(cachedValue == null) { cachedValue = defaultFormat.format(number); } return cachedValue; } public TemplateModel get(String key) { return new SimpleScalar(env.getNumberFormatObject(key).format(number)); } public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 1) { throw new TemplateModelException( "number?string(...) requires exactly 1 argument."); } return get((String) arguments.get(0)); } public boolean isEmpty() { return false; } } private static class DateFormatter implements TemplateScalarModel, TemplateHashModel, TemplateMethodModel { private final Date date; private final int dateType; private final Environment env; private final DateFormat defaultFormat; private String cachedValue; DateFormatter(Date date, int dateType, Environment env) throws TemplateModelException { this.date = date; this.dateType = dateType; this.env = env; defaultFormat = env.getDateFormatObject(dateType); } public String getAsString() throws TemplateModelException { if(dateType == TemplateDateModel.UNKNOWN) { throw new TemplateModelException("Can't convert the date to string, because it is not known which parts of the date variable are in use. Use ?date, ?time or ?datetime built-in, or ?string. or ?string(format) built-in with this date."); } if(cachedValue == null) { cachedValue = defaultFormat.format(date); } return cachedValue; } public TemplateModel get(String key) throws TemplateModelException { return new SimpleScalar(env.getDateFormatObject(dateType, key).format(date)); } public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 1) { throw new TemplateModelException( "date?string(...) requires exactly 1 argument."); } return get((String) arguments.get(0)); } public boolean isEmpty() { return false; } } private static class BooleanFormatter implements TemplateScalarModel, TemplateMethodModel { private final TemplateBooleanModel bool; private final Environment env; BooleanFormatter(TemplateBooleanModel bool, Environment env) { this.bool = bool; this.env = env; } public String getAsString() throws TemplateModelException { if (bool instanceof TemplateScalarModel) { return ((TemplateScalarModel) bool).getAsString(); } else { return env.getBooleanFormat(bool.getAsBoolean()); } } public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 2) { throw new TemplateModelException( "boolean?string(...) requires exactly " + "2 arguments."); } return new SimpleScalar( (String) arguments.get(bool.getAsBoolean() ? 0 : 1)); } } } static class trimBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(s.trim()); } } static class htmlBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.HTMLEnc(s)); } } static class xmlBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.XMLEnc(s)); } } static class xhtmlBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.XHTMLEnc(s)); } } static class rtfBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new SimpleScalar(StringUtil.RTFEnc(s)); } } static class urlBI extends StringBuiltIn { TemplateModel calculateResult(String s, Environment env) { return new urlBIResult(s, env); } static class urlBIResult implements TemplateScalarModel, TemplateMethodModel { private final String target; private final Environment env; private String cachedResult; private urlBIResult(String target, Environment env) { this.target = target; this.env = env; } public String getAsString() throws TemplateModelException { if (cachedResult == null) { String cs = env.getEffectiveURLEscapingCharset(); if (cs == null) { throw new TemplateModelException( "To do URL encoding, the framework that encloses " + "FreeMarker must specify the output encoding " + "or the URL encoding charset, so ask the " + "programmers to fix it. Or, as a last chance, " + "you can set the url_encoding_charset setting in " + "the template, e.g. " + "<#setting url_escaping_charset='ISO-8859-1'>, or " + "give the charset explicitly to the buit-in, e.g. " + "foo?url('ISO-8859-1')."); } try { cachedResult = StringUtil.URLEnc(target, cs); } catch (UnsupportedEncodingException e) { throw new TemplateModelException( "Failed to execute URL encoding.", e); } } return cachedResult; } public Object exec(List args) throws TemplateModelException { if (args.size() != 1) { throw new TemplateModelException("The \"url\" built-in " + "needs exactly 1 parameter, the charset."); } try { return new SimpleScalar( StringUtil.URLEnc(target, (String) args.get(0))); } catch (UnsupportedEncodingException e) { throw new TemplateModelException( "Failed to execute URL encoding.", e); } } } } static class keysBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateHashModelEx) { TemplateCollectionModel keys = ((TemplateHashModelEx) model).keys(); assertNonNull(keys, this, env); if (!(keys instanceof TemplateSequenceModel)) keys = new CollectionAndSequence(keys); return keys; } throw invalidTypeException(model, target, env, "extended hash"); } } static class valuesBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateHashModelEx) { TemplateCollectionModel values = ((TemplateHashModelEx) model).values(); assertNonNull(values, this, env); if (!(values instanceof TemplateSequenceModel)) values = new CollectionAndSequence(values); return values; } throw invalidTypeException(model, target, env, "extended hash"); } } static class sizeBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateSequenceModel) { int size = ((TemplateSequenceModel) model).size(); return new SimpleNumber(size); } if (model instanceof TemplateHashModelEx) { int size = ((TemplateHashModelEx) model).size(); return new SimpleNumber(size); } throw invalidTypeException(model, target, env, "extended-hash or sequence"); } } static class existsBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { try { TemplateModel model = target.getAsTemplateModel(env); return model==null ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE; } catch (InvalidReferenceException ire) { if (target instanceof ParentheticalExpression) { return TemplateBooleanModel.FALSE; } throw ire; } } boolean isTrue(Environment env) throws TemplateException { return _getAsTemplateModel(env) == TemplateBooleanModel.TRUE; } } static class has_contentBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { try { TemplateModel model = target.getAsTemplateModel(env); return Expression.isEmpty(model) ? TemplateBooleanModel.FALSE : TemplateBooleanModel.TRUE; } catch (InvalidReferenceException ire) { if (target instanceof ParentheticalExpression) { return TemplateBooleanModel.FALSE; } throw ire; } } boolean isTrue(Environment env) throws TemplateException { return _getAsTemplateModel(env) == TemplateBooleanModel.TRUE; } } static class if_existsBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { try { TemplateModel model = target.getAsTemplateModel(env); return model == null ? TemplateModel.NOTHING : model; } catch (InvalidReferenceException ire) { if (target instanceof ParentheticalExpression) { return TemplateModel.NOTHING; } throw ire; } } } static class is_stringBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateScalarModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_numberBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateNumberModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_nodeBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateNodeModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_booleanBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateBooleanModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_dateBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateDateModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_methodBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateMethodModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_macroBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof Macro) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_transformBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateTransformModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_hashBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateHashModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_hash_exBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateHashModelEx) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_sequenceBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateSequenceModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_collectionBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateCollectionModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_indexableBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateSequenceModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_enumerableBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateSequenceModel || tm instanceof TemplateCollectionModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class is_directiveBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); assertNonNull(tm, target, env); return (tm instanceof TemplateTransformModel || tm instanceof Macro || tm instanceof TemplateDirectiveModel) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } static class namespaceBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel tm = target.getAsTemplateModel(env); if (!(tm instanceof Macro)) { invalidTypeException(tm, target, env, "macro"); } return env.getMacroNamespace((Macro) tm); } } static class defaultBI extends BuiltIn { TemplateModel _getAsTemplateModel(final Environment env) throws TemplateException { try { TemplateModel model = target.getAsTemplateModel(env); return model == null ? FIRST_NON_NULL_METHOD : new ConstantMethod(model); } catch (InvalidReferenceException ire) { if (target instanceof ParentheticalExpression) { return FIRST_NON_NULL_METHOD; } throw ire; } } private static class ConstantMethod implements TemplateMethodModelEx { private final TemplateModel constant; ConstantMethod(TemplateModel constant) { this.constant = constant; } public Object exec(List args) { return constant; } } /** * A method that goes through the arguments one by one and returns * the first one that is non-null. If all args are null, returns null. */ private static final TemplateMethodModelEx FIRST_NON_NULL_METHOD = new TemplateMethodModelEx() { public Object exec(List args) throws TemplateModelException { if(args.isEmpty()) { throw new TemplateModelException( "?default(arg) expects at least one argument."); } TemplateModel result = null; for (int i = 0; i< args.size(); i++ ) { result = (TemplateModel) args.get(i); if (result != null) { break; } } return result; } }; } static class containsBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { Object obj; String sub; int ln = args.size(); if (ln != 1) { throw new TemplateModelException( "?contains(...) expects one argument."); } obj = args.get(0); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?contains(...) expects a string as " + "its first argument."); } sub = ((TemplateScalarModel) obj).getAsString(); return (s.indexOf(sub) != -1) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } } static class index_ofBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { Object obj; String sub; int fidx; int ln = args.size(); if (ln == 0) { throw new TemplateModelException( "?index_of(...) expects at least one argument."); } if (ln > 2) { throw new TemplateModelException( "?index_of(...) expects at most two arguments."); } obj = args.get(0); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?index_of(...) expects a string as " + "its first argument."); } sub = ((TemplateScalarModel) obj).getAsString(); if (ln > 1) { obj = args.get(1); if (!(obj instanceof TemplateNumberModel)) { throw new TemplateModelException( "?index_of(...) expects a number as " + "its second argument."); } fidx = ((TemplateNumberModel) obj).getAsNumber().intValue(); } else { fidx = 0; } return new SimpleNumber(s.indexOf(sub, fidx)); } } } static class last_index_ofBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { Object obj; String sub; int ln = args.size(); if (ln == 0) { throw new TemplateModelException( "?last_index_of(...) expects at least one argument."); } if (ln > 2) { throw new TemplateModelException( "?last_index_of(...) expects at most two arguments."); } obj = args.get(0); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?last_index_of(...) expects a string as " + "its first argument."); } sub = ((TemplateScalarModel) obj).getAsString(); if (ln > 1) { obj = args.get(1); if (!(obj instanceof TemplateNumberModel)) { throw new TemplateModelException( "?last_index_of(...) expects a number as " + "its second argument."); } int fidx = ((TemplateNumberModel) obj).getAsNumber().intValue(); return new SimpleNumber(s.lastIndexOf(sub, fidx)); } else { return new SimpleNumber(s.lastIndexOf(sub)); } } } } static class starts_withBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { String sub; if (args.size() != 1) { throw new TemplateModelException( "?starts_with(...) expects exactly 1 argument."); } Object obj = args.get(0); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?starts_with(...) expects a string argument"); } sub = ((TemplateScalarModel) obj).getAsString(); return s.startsWith(sub) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } } static class ends_withBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { String sub; if (args.size() != 1) { throw new TemplateModelException( "?ends_with(...) expects exactly 1 argument."); } Object obj = args.get(0); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?ends_with(...) expects a string argument"); } sub = ((TemplateScalarModel) obj).getAsString(); return s.endsWith(sub) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } } } static class replaceBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModel { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { int numArgs = args.size(); if (numArgs < 2 || numArgs > 3) { throw new TemplateModelException( "?replace(...) needs 2 or 3 arguments."); } String first = (String) args.get(0); String second = (String) args.get(1); String flags = numArgs >2 ? (String) args.get(2) : ""; boolean caseInsensitive = flags.indexOf('i') >=0; boolean firstOnly = flags.indexOf('f') >=0; if (flags.indexOf('r') >=0) { throw new TemplateModelException("The regular expression classes are not available."); } return new SimpleScalar(StringUtil.replace( s, first, second, caseInsensitive, firstOnly)); } } } static class splitBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModel { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { int numArgs = args.size(); if (numArgs != 1 && numArgs !=2) { throw new TemplateModelException( "?split(...) expects 1 or 2 arguments."); } String splitString = (String) args.get(0); String flags = numArgs ==2 ? (String) args.get(1) : ""; boolean caseInsensitive = flags.indexOf('i') >=0; if (flags.indexOf('r') >=0) { throw new TemplateModelException("regular expression classes not available"); } return new StringArraySequence(StringUtil.split( s, splitString, caseInsensitive)); } } } static class left_padBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { Object obj; int ln = args.size(); if (ln == 0) { throw new TemplateModelException( "?left_pad(...) expects at least 1 argument."); } if (ln > 2) { throw new TemplateModelException( "?left_pad(...) expects at most 2 arguments."); } obj = args.get(0); if (!(obj instanceof TemplateNumberModel)) { throw new TemplateModelException( "?left_pad(...) expects a number as " + "its 1st argument."); } int width = ((TemplateNumberModel) obj).getAsNumber().intValue(); if (ln > 1) { obj = args.get(1); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?left_pad(...) expects a string as " + "its 2nd argument."); } String filling = ((TemplateScalarModel) obj).getAsString(); try { return new SimpleScalar(StringUtil.leftPad(s, width, filling)); } catch (IllegalArgumentException e) { if (filling.length() == 0) { throw new TemplateModelException( "The 2nd argument of ?left_pad(...) " + "can't be a 0 length string."); } else { throw new TemplateModelException( "Error while executing the ?left_pad(...) " + "built-in.", e); } } } else { return new SimpleScalar(StringUtil.leftPad(s, width)); } } } } static class right_padBI extends BuiltIn { TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { TemplateModel model = target.getAsTemplateModel(env); if (model instanceof TemplateScalarModel) { return new BIMethod(((TemplateScalarModel) model).getAsString()); } throw invalidTypeException(model, target, env, "string"); } private static class BIMethod implements TemplateMethodModelEx { private String s; private BIMethod(String s) { this.s = s; } public Object exec(List args) throws TemplateModelException { Object obj; int ln = args.size(); if (ln == 0) { throw new TemplateModelException( "?right_pad(...) expects at least 1 argument."); } if (ln > 2) { throw new TemplateModelException( "?right_pad(...) expects at most 2 arguments."); } obj = args.get(0); if (!(obj instanceof TemplateNumberModel)) { throw new TemplateModelException( "?right_pad(...) expects a number as " + "its 1st argument."); } int width = ((TemplateNumberModel) obj).getAsNumber().intValue(); if (ln > 1) { obj = args.get(1); if (!(obj instanceof TemplateScalarModel)) { throw new TemplateModelException( "?right_pad(...) expects a string as " + "its 2nd argument."); } String filling = ((TemplateScalarModel) obj).getAsString(); try { return new SimpleScalar(StringUtil.rightPad(s, width, filling)); } catch (IllegalArgumentException e) { if (filling.length() == 0) { throw new TemplateModelException( "The 2nd argument of ?right_pad(...) " + "can't be a 0 length string."); } else { throw new TemplateModelException( "Error while executing the ?right_pad(...) " + "built-in.", e); } } } else { return new SimpleScalar(StringUtil.rightPad(s, width)); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/core/IfBlock.java0000644000175000017500000001062411723544471023657 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.ArrayList; import java.io.IOException; import freemarker.template.TemplateException; /** * A instruction that handles if-elseif-else blocks. * @author Jonathan Revusky */ final class IfBlock extends TemplateElement { IfBlock(ConditionalBlock block) { nestedElements = new ArrayList(); addBlock(block); } void addBlock(ConditionalBlock block) { nestedElements.add(block); } void accept(Environment env) throws TemplateException, IOException { for (int i = 0; i"); return buf.toString(); } TemplateElement postParseCleanup(boolean stripWhitespace) throws ParseException { if (nestedElements.size() == 1) { ConditionalBlock cblock = (ConditionalBlock) nestedElements.get(0); cblock.isSimple = true; cblock.setLocation(getTemplate(), cblock, this); return cblock.postParseCleanup(stripWhitespace); } else { return super.postParseCleanup(stripWhitespace); } } public String getDescription() { return "if-else "; } } libfreemarker-java-2.3.19.orig/src/freemarker/core/package.html0000644000175000017500000000044611723544471023765 0ustar ebourgebourg

This package contains FreeMarker's core parsing/rendering functionality; most casual users do not need to be aware of the classes in this package, and can restrict their attention to the {@link freemarker.template} package.

libfreemarker-java-2.3.19.orig/src/freemarker/core/CompressedBlock.java0000644000175000017500000000721311723544472025426 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.*; import freemarker.template.utility.StandardCompress; import java.io.*; /** * An instruction that reduces all sequences of whitespace to a single * space or newline. In addition, leading and trailing whitespace is removed. * @version $Id: CompressedBlock.java,v 1.1 2003/04/22 21:05:00 revusky Exp $ * @see freemarker.template.utility.StandardCompress */ final class CompressedBlock extends TemplateElement { CompressedBlock(TemplateElement nestedBlock) { this.nestedBlock = nestedBlock; } void accept(Environment env) throws TemplateException, IOException { if (nestedBlock != null) { env.visit(nestedBlock, StandardCompress.INSTANCE, null); } } public String getCanonicalForm() { String nested = nestedBlock != null ? nestedBlock.getCanonicalForm() : ""; return "<#compress>" + nested + ""; } public String getDescription() { return "compressed block"; } boolean isIgnorable() { return nestedBlock == null || nestedBlock.isIgnorable(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/MixedContent.java0000644000175000017500000001033111723544470024741 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import java.util.*; import java.io.IOException; import freemarker.template.TemplateException; /** * Encapsulates an array of TemplateElement objects. */ final class MixedContent extends TemplateElement { MixedContent() { nestedElements = new ArrayList(); } void addElement(TemplateElement element) { nestedElements.add(element); } TemplateElement postParseCleanup(boolean stripWhitespace) throws ParseException { super.postParseCleanup(stripWhitespace); if (nestedElements.size() == 1) { return (TemplateElement) nestedElements.get(0); } return this; } /** * Processes the contents of the internal TemplateElement list, * and outputs the resulting text. */ void accept(Environment env) throws TemplateException, IOException { for (int i=0; i 3 && (value.indexOf("${") >= 0 || value.indexOf("#{") >= 0)) { SimpleCharStream scs = new SimpleCharStream(new StringReader(value), beginLine, beginColumn+1, value.length()); FMParserTokenManager token_source = new FMParserTokenManager(scs); token_source.onlyTextOutput = true; FMParser parser = new FMParser(token_source); parser.template = getTemplate(); try { interpolatedOutput = parser.FreeMarkerText(); } catch(ParseException e) { e.setTemplateName(getTemplate().getName()); throw e; } this.constantValue = null; } } TemplateModel _getAsTemplateModel(Environment env) throws TemplateException { return new SimpleScalar(getStringValue(env)); } public String getAsString() { return value; } String getStringValue(Environment env) throws TemplateException { if (interpolatedOutput == null) { return value; } else { TemplateExceptionHandler teh = env.getTemplateExceptionHandler(); env.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); try { return env.renderElementToString(interpolatedOutput); } catch (IOException ioe) { throw new TemplateException(ioe, env); } finally { env.setTemplateExceptionHandler(teh); } } } public String getCanonicalForm() { // return "\"" + StringUtil.FTLStringLiteralEnc(value) + "\""; return "\"" + escapeString(value) + "\""; } boolean isLiteral() { return interpolatedOutput == null; } Expression _deepClone(String name, Expression subst) { StringLiteral cloned = new StringLiteral(value); cloned.interpolatedOutput = this.interpolatedOutput; return cloned; } static private String escapeString(String s) { if (s.indexOf('"') == -1) { return s; } java.util.StringTokenizer st = new java.util.StringTokenizer(s, "\"", true); StringBuffer buf = new StringBuffer(); while (st.hasMoreTokens()) { String tok = st.nextToken(); if (tok.equals("\"")) { buf.append('\\'); } buf.append(tok); } return buf.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/core/CustomAttribute.java0000644000175000017500000001621711723544470025507 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.core; import freemarker.template.Template; /** * A class that allows one to associate custom data with a configuration, * a template, or environment. It works pretty much like {@link ThreadLocal}, a * class that allows one to associate custom data with a thread. * @author Attila Szegedi * @version $Id: CustomAttribute.java,v 1.3 2003/11/10 14:05:22 ddekany Exp $ */ public class CustomAttribute { /** * Constant used in the constructor specifying that this attribute is * scoped by the environment. */ public static final int SCOPE_ENVIRONMENT = 0; /** * Constant used in the constructor specifying that this attribute is * scoped by the template. */ public static final int SCOPE_TEMPLATE = 1; /** * Constant used in the constructor specifying that this attribute is * scoped by the configuration. */ public static final int SCOPE_CONFIGURATION = 2; // We use an internal key instead of 'this' so that malicious subclasses // overriding equals() and hashCode() can't gain access to other attribute // values. That's also the reason why get() and set() are marked final. private final Object key = new Object(); private final int scope; /** * Creates a new custom attribute with the specified scope * @param scope one of SCOPE_ constants. */ public CustomAttribute(int scope) { if(scope != SCOPE_ENVIRONMENT && scope != SCOPE_TEMPLATE && scope != SCOPE_CONFIGURATION) { throw new IllegalArgumentException(); } this.scope = scope; } /** * This method is invoked when {@link #get()} is invoked without * {@link #set(Object)} being invoked before it to define the value in the * current scope. Override it to create the attribute value on-demand. * @return the initial value for the custom attribute. By default returns null. */ protected Object create() { return null; } /** * @return the value of the attribute in the context of the current environment. * @throws IllegalStateException if there is no current environment (and * hence also no current template and configuration), therefore the * attribute's current scope object can't be resolved. */ public final Object get() { return getScopeConfigurable().getCustomAttribute(key, this); } /** * @return the value of a template-scope attribute in the context of a * given template. * @throws UnsupportedOperationException if this custom attribute is not a * template-scope attribute * @throws NullPointerException if t is null */ public final Object get(Template t) { if(scope != SCOPE_TEMPLATE) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } return ((Configurable)t).getCustomAttribute(key, this); } /** * Sets the value of the attribute in the context of the current environment. * @param value the new value of the attribute * @throws IllegalStateException if there is no current environment (and * hence also no current template and configuration), therefore the * attribute's current scope object can't be resolved. */ public final void set(Object value) { getScopeConfigurable().setCustomAttribute(key, value); } /** * Sets the value of a template-scope attribute in the context of the given * template. * @param value the new value of the attribute * @param t the template * @throws UnsupportedOperationException if this custom attribute is not a * template-scope attribute * @throws NullPointerException if t is null */ public final void set(Object value, Template t) { if(scope != SCOPE_TEMPLATE) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } ((Configurable)t).setCustomAttribute(key, value); } private Configurable getScopeConfigurable() { Configurable c = Environment.getCurrentEnvironment(); if(c == null) { throw new IllegalStateException("No current environment"); } switch(scope) { case SCOPE_ENVIRONMENT: { return c; } case SCOPE_TEMPLATE: { return c.getParent(); } case SCOPE_CONFIGURATION: { return c.getParent().getParent(); } default: { throw new Error(); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/0000755000175000017500000000000012164627123022357 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/test-xmlns3.xml0000644000175000017500000000046511723544471025313 0ustar ebourgebourg Test Book Ch1 p1.1 p1.2 p1.3 Ch2 p2.1 p2.2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/TemplateTestCase.java0000644000175000017500000004745411723544467026460 0ustar ebourgebourg/* * Copyright (c) 2005 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; import java.util.StringTokenizer; import java.util.TimeZone; import java.util.TreeSet; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import junit.framework.TestCase; import org.jdom.input.SAXBuilder; import org.xml.sax.InputSource; import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.ResourceBundleModel; import freemarker.ext.dom.NodeModel; import freemarker.ext.jdom.NodeListModel; import freemarker.template.Configuration; import freemarker.template.SimpleCollection; import freemarker.template.SimpleDate; import freemarker.template.SimpleNumber; import freemarker.template.Template; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateException; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateNodeModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.StringUtil; import freemarker.testcase.models.BooleanHash1; import freemarker.testcase.models.BooleanHash2; import freemarker.testcase.models.BooleanList1; import freemarker.testcase.models.BooleanList2; import freemarker.testcase.models.MultiModel1; import freemarker.testcase.models.VarArgTestModel; public class TemplateTestCase extends TestCase { Template template; HashMap dataModel = new HashMap(); String filename, testName; String inputDir = "template"; String referenceDir = "reference"; File outputDir; Configuration conf = new Configuration(); public TemplateTestCase(String name, String filename) { super(name); this.filename = filename; this.testName = name; } public void setTemplateDirectory(String dirname) throws IOException { URL url = getClass().getResource("TemplateTestCase.class"); File parent = new File(url.getFile()).getParentFile(); File dir = new File(parent, dirname); conf.setDirectoryForTemplateLoading(dir); System.out.println("Setting loading directory as: " + dir); } public void setOutputDirectory(String dirname) { URL url = getClass().getResource("TemplateTestCase.class"); File parent = new File(url.getFile()).getParentFile(); this.outputDir = new File(parent, dirname); System.out.println("Setting reference directory as: " + outputDir); } public void setConfigParam(String param, String value) throws IOException { if ("templatedir".equals(param)) { setTemplateDirectory(value); } else if ("auto_import".equals(param)) { StringTokenizer st = new StringTokenizer(value); if (!st.hasMoreTokens()) fail("Expecting libname"); String libname = st.nextToken(); if (!st.hasMoreTokens()) fail("Expecting 'as ' in autoimport"); String as = st.nextToken(); if (!as.equals("as")) fail("Expecting 'as ' in autoimport"); if (!st.hasMoreTokens()) fail("Expecting alias after 'as' in autoimport"); String alias = st.nextToken(); conf.addAutoImport(alias, libname); } else if ("clear_encoding_map".equals(param)) { if (StringUtil.getYesNo(value)) { conf.clearEncodingMap(); } } else if ("input_encoding".equals(param)) { conf.setDefaultEncoding(value); } else if ("outputdir".equals(param)) { setOutputDirectory(value); } else { try { conf.setSetting(param, value); } catch (TemplateException e) { throw new RuntimeException( "Failed to set setting " + StringUtil.jQuote(param) + " to " + StringUtil.jQuote(value) + "; see cause exception.", e); } } } /* * This method just contains all the code to seed the data model * ported over from the individual classes. This seems ugly and unnecessary. * We really might as well just expose pretty much * the same tree to all our tests. (JR) */ public void setUp() throws Exception { dataModel.put("message", "Hello, world!"); if (testName.equals("bean-maps")) { BeansWrapper w1 = new BeansWrapper(); BeansWrapper w2 = new BeansWrapper(); BeansWrapper w3 = new BeansWrapper(); BeansWrapper w4 = new BeansWrapper(); BeansWrapper w5 = new BeansWrapper(); BeansWrapper w6 = new BeansWrapper(); BeansWrapper w7 = new BeansWrapper(); w1.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY); w2.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY); w3.setExposureLevel(BeansWrapper.EXPOSE_NOTHING); w4.setExposureLevel(BeansWrapper.EXPOSE_NOTHING); w5.setExposureLevel(BeansWrapper.EXPOSE_ALL); w6.setExposureLevel(BeansWrapper.EXPOSE_ALL); w1.setMethodsShadowItems(true); w2.setMethodsShadowItems(false); w3.setMethodsShadowItems(true); w4.setMethodsShadowItems(false); w5.setMethodsShadowItems(true); w6.setMethodsShadowItems(false); w7.setSimpleMapWrapper(true); Object test = getTestBean(); dataModel.put("m1", w1.wrap(test)); dataModel.put("m2", w2.wrap(test)); dataModel.put("m3", w3.wrap(test)); dataModel.put("m4", w4.wrap(test)); dataModel.put("m5", w5.wrap(test)); dataModel.put("m6", w6.wrap(test)); dataModel.put("m7", w7.wrap(test)); dataModel.put("s1", w1.wrap("hello")); dataModel.put("s2", w1.wrap("world")); dataModel.put("s3", w5.wrap("hello")); dataModel.put("s4", w5.wrap("world")); } else if (testName.equals("beans")) { dataModel.put("array", new String[] { "array-0", "array-1"}); dataModel.put("list", Arrays.asList(new String[] { "list-0", "list-1", "list-2"})); Map tmap = new HashMap(); tmap.put("key", "value"); Object objKey = new Object(); tmap.put(objKey, "objValue"); dataModel.put("map", tmap); dataModel.put("objKey", objKey); dataModel.put("obj", TestCase.class.getClassLoader().loadClass( "freemarker.testcase.models.BeanTestClass").newInstance()); // Why reflection: The target class is excluded from Eclipse // build-path as it uses Java 5. dataModel.put("resourceBundle", new ResourceBundleModel(ResourceBundle.getBundle("freemarker.testcase.models.BeansTestResources"), BeansWrapper.getDefaultInstance())); dataModel.put("date", new GregorianCalendar(1974, 10, 14).getTime()); dataModel.put("statics", BeansWrapper.getDefaultInstance().getStaticModels()); dataModel.put("enums", BeansWrapper.getDefaultInstance().getEnumModels()); } else if (testName.equals("boolean")) { dataModel.put( "boolean1", TemplateBooleanModel.FALSE); dataModel.put( "boolean2", TemplateBooleanModel.TRUE); dataModel.put( "boolean3", TemplateBooleanModel.TRUE); dataModel.put( "boolean4", TemplateBooleanModel.TRUE); dataModel.put( "boolean5", TemplateBooleanModel.FALSE); dataModel.put( "list1", new BooleanList1() ); dataModel.put( "list2", new BooleanList2() ); dataModel.put( "hash1", new BooleanHash1() ); dataModel.put( "hash2", new BooleanHash2() ); } else if (testName.equals("dateformat")) { GregorianCalendar cal = new GregorianCalendar(2002, 10, 15, 14, 54, 13); cal.setTimeZone(TimeZone.getTimeZone("GMT")); dataModel.put("date", new SimpleDate(cal.getTime(), TemplateDateModel.DATETIME)); dataModel.put("unknownDate", new SimpleDate(cal.getTime(), TemplateDateModel.UNKNOWN)); } else if (testName.equals("number-format")) { dataModel.put("int", new SimpleNumber(new Integer(1))); dataModel.put("double", new SimpleNumber(new Double(1.0))); dataModel.put("double2", new SimpleNumber(new Double(1 + 1e-15))); dataModel.put("double3", new SimpleNumber(new Double(1e-16))); dataModel.put("double4", new SimpleNumber(new Double(-1e-16))); dataModel.put("bigDecimal", new SimpleNumber(java.math.BigDecimal.valueOf(1))); dataModel.put("bigDecimal2", new SimpleNumber(java.math.BigDecimal.valueOf(1, 16))); } else if (testName.equals("default-xmlns")) { InputSource is = new InputSource(getClass().getResourceAsStream("test-defaultxmlns1.xml")); NodeModel nm = NodeModel.parse(is); dataModel.put("doc", nm); } else if (testName.equals("multimodels")) { dataModel.put("test", "selftest"); dataModel.put("self", "self"); dataModel.put("zero", new Integer(0)); dataModel.put("data", new MultiModel1()); } else if (testName.equals("nodelistmodel")) { org.jdom.Document doc = new SAXBuilder().build(new InputSource(getClass().getResourceAsStream("test-xml.xml"))); dataModel.put("doc", new NodeListModel(doc)); } else if (testName.equals("test-stringbimethods")) { dataModel.put("multi", new TestBoolean()); } else if (testName.equals("type-builtins")) { dataModel.put("testmethod", new TestMethod()); dataModel.put("testnode", new TestNode()); dataModel.put("testcollection", new SimpleCollection(new ArrayList())); } else if (testName.equals("var-layers")) { dataModel.put("x", new Integer(4)); dataModel.put("z", new Integer(4)); conf.setSharedVariable("y", new Integer(7)); } else if (testName.equals("xml-fragment")) { DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); f.setNamespaceAware(true); DocumentBuilder db = f.newDocumentBuilder(); org.w3c.dom.Document doc = db.parse(new InputSource(getClass().getResourceAsStream("test-xmlfragment.xml"))); dataModel.put("node", NodeModel.wrap(doc.getDocumentElement().getFirstChild().getFirstChild())); } else if (testName.equals("xmlns1")) { InputSource is = new InputSource(getClass().getResourceAsStream("test-xmlns.xml")); NodeModel nm = NodeModel.parse(is); dataModel.put("doc", nm); } else if (testName.equals("xmlns2")) { InputSource is = new InputSource(getClass().getResourceAsStream("test-xmlns2.xml")); NodeModel nm = NodeModel.parse(is); dataModel.put("doc", nm); } else if (testName.equals("xmlns3") || testName.equals("xmlns4")) { InputSource is = new InputSource(getClass().getResourceAsStream("test-xmlns3.xml")); NodeModel nm = NodeModel.parse(is); dataModel.put("doc", nm); } else if (testName.equals("xmlns5")) { InputSource is = new InputSource(getClass().getResourceAsStream("test-defaultxmlns1.xml")); NodeModel nm = NodeModel.parse(is); dataModel.put("doc", nm); } else if (testName.startsWith("sequence-builtins-with-")) { Set abcSet = new TreeSet(); abcSet.add("a"); abcSet.add("b"); abcSet.add("c"); dataModel.put("abcSet", abcSet); } else if (testName.equals("test-iso8601")) { dataModel.put("javaGMT02", TimeZone.getTimeZone("GMT+02")); dataModel.put("javaUTC", TimeZone.getTimeZone("UTC")); dataModel.put("adaptedToStringScalar", new Object() { public String toString() { return "GMT+02"; } }); } else if (testName.equals("test-number-to-date")) { dataModel.put("bigInteger", new BigInteger("1305575275540")); dataModel.put("bigDecimal", new BigDecimal("1305575275539.5")); } else if (testName.equals("test-varargs")) { dataModel.put("m", new VarArgTestModel()); } } public void runTest() { try { template = conf.getTemplate(filename); } catch (Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); fail("Could not load template " + filename + "\n" + sw.toString()); } File refFile = new File (outputDir, filename); File outFile = new File (outputDir, filename+".out"); Writer out = null; String encoding = conf.getOutputEncoding(); if (encoding == null) encoding = "UTF-8"; try { out = new OutputStreamWriter(new FileOutputStream(outFile), encoding); } catch (IOException ioe) { fail("Cannot write to file: " + outFile + "\n" + ioe.getMessage()); } try { template.process(dataModel, out); out.close(); } catch (Exception e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); fail("Could not process template " + filename + "\n" + sw.toString()); } try { Reader ref = new InputStreamReader(new FileInputStream(refFile), encoding); Reader output = new InputStreamReader(new FileInputStream(outFile), encoding); System.out.println(outFile); compare(ref, output); outFile.delete(); } catch (IOException e) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); fail("Error comparing files " + refFile + " and " + outFile + "\n" + sw.toString()); } } static public void compare(Reader reference, Reader output) throws IOException { LineNumberReader ref = new LineNumberReader(reference); LineNumberReader out = new LineNumberReader(output); String refLine = "", outLine = ""; while (refLine != null || outLine != null) { if (refLine == null) { fail("Output text is longer than reference text"); } if (outLine == null) { fail("Output text is shorter than reference text"); } refLine = ref.readLine(); outLine = out.readLine(); if (refLine != null && outLine != null & !refLine.equals(outLine)) { fail("Difference found on line " + ref.getLineNumber() + ".\nReference text is: " + refLine + "\nOutput text is: " + outLine); } } } static class TestBoolean implements TemplateBooleanModel, TemplateScalarModel { public boolean getAsBoolean() { return true; } public String getAsString() { return "de"; } } static class TestMethod implements TemplateMethodModel { public Object exec(java.util.List arguments) { return "x"; } } static class TestNode implements TemplateNodeModel { public String getNodeName() { return "name"; } public TemplateNodeModel getParentNode() { return null; } public String getNodeType() { return "element"; } public TemplateSequenceModel getChildNodes() { return null; } public String getNodeNamespace() { return null; } } public Object getTestBean() { Map testBean = new TestBean(); testBean.put("name", "Chris"); testBean.put("location", "San Francisco"); testBean.put("age", new Integer(27)); return testBean; } public static class TestBean extends HashMap { public String getName() { return "Christopher"; } public int getLuckyNumber() { return 7; } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/0000755000175000017500000000000012164627123024226 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/TestJspTaglibs.java0000644000175000017500000004437511723544471030014 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.servlets; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.InputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.net.URL; import java.security.Principal; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionContext; import junit.framework.TestCase; import freemarker.ext.servlet.FreemarkerServlet; import freemarker.template.TemplateException; import freemarker.testcase.TemplateTestCase; /** * @version $Id: TestJspTaglibs.java,v 1.13 2005/06/12 00:44:39 revusky Exp $ * @author Attila Szegedi */ public class TestJspTaglibs extends TestCase { File refFile; public TestJspTaglibs(String name) { super(name); } public TestJspTaglibs(String name, String filename) { super(name); } public void setUp() throws Exception { URL url = TestJspTaglibs.class.getResource("TestJspTaglibs.class"); File thisDir = new File(url.getFile()).getParentFile(); refFile = new File(thisDir, "reference/test-jsptaglibs.txt"); } public void runTest() throws TemplateException { try { ServletConfig cfg = new MockServletConfig(); FreemarkerServlet servlet = new FreemarkerServlet(); servlet.init(cfg); MockRequest req = new MockRequest("test-jsptaglibs.txt"); MockResponse resp = new MockResponse(); servlet.doGet(req, resp); StringReader output = new StringReader(resp.toString()); Reader reference = new FileReader(refFile); System.out.println(resp.toString()); TemplateTestCase.compare(reference,output); } catch(Exception e) { e.printStackTrace(); throw new TemplateException(e, null); } } private static class MockServletConfig implements ServletConfig, ServletContext { private final Properties initParams = new Properties(); private final Hashtable attributes = new Hashtable(); MockServletConfig() { initParams.setProperty("TemplatePath", "/template/"); initParams.setProperty("NoCache", "true"); initParams.setProperty("TemplateUpdateInterval", "0"); initParams.setProperty("DefaultEncoding", "UTF-8"); initParams.setProperty("ObjectWrapper", "beans"); } public String getInitParameter(String name) { return initParams.getProperty(name); } public Enumeration getInitParameterNames() { return initParams.keys(); } public ServletContext getServletContext() { return this; } public String getContextPath() { throw new UnsupportedOperationException(); } public String getServletName() { return "freemarker"; } public Object getAttribute(String arg0) { return attributes.get(arg0); } public Enumeration getAttributeNames() { return attributes.keys(); } public ServletContext getContext(String arg0) { throw new UnsupportedOperationException(); } public int getMajorVersion() { return 0; } public String getMimeType(String arg0) { throw new UnsupportedOperationException(); } public int getMinorVersion() { return 0; } public RequestDispatcher getNamedDispatcher(String arg0) { throw new UnsupportedOperationException(); } public String getRealPath(String arg0) { return null; } public RequestDispatcher getRequestDispatcher(String arg0) { throw new UnsupportedOperationException(); } public URL getResource(String url) { if (url.startsWith("/")) { url = url.substring(1); } return getClass().getResource(url); } public InputStream getResourceAsStream(String url) { if (url.startsWith("/")) { url = url.substring(1); } return getClass().getResourceAsStream(url); } public Set getResourcePaths(String path) { if(path.equals("/WEB-INF")) { return new HashSet(Arrays.asList(new String[] { "/WEB-INF/fmtesttag2.tld", "/WEB-INF/lib/" })); } else if(path.equals("/WEB-INF/lib")) { return new HashSet(Arrays.asList(new String[] { "/WEB-INF/lib/taglib-foo.jar", })); } else { return null; } } public String getServerInfo() { return "FreeMarker/JUnit"; } /** * @deprecated */ public Servlet getServlet(String arg0) { throw new UnsupportedOperationException(); } public String getServletContextName() { return "freemarker"; } /** * @deprecated */ public Enumeration getServletNames() { throw new UnsupportedOperationException(); } /** * @deprecated */ public Enumeration getServlets() { throw new UnsupportedOperationException(); } /** * @deprecated */ public void log(Exception arg0, String arg1) { } public void log(String arg0, Throwable arg1) { } public void log(String arg0) { } public void removeAttribute(String arg0) { attributes.remove(arg0); } public void setAttribute(String arg0, Object arg1) { attributes.put(arg0, arg1); } } private static final class MockRequest implements HttpServletRequest { private final String pathInfo; private HttpSession session; MockRequest(String pathInfo) { this.pathInfo = pathInfo; } public int getLocalPort() { throw new UnsupportedOperationException(); } public String getLocalAddr() { throw new UnsupportedOperationException(); } public String getLocalName() { throw new UnsupportedOperationException(); } public int getRemotePort() { throw new UnsupportedOperationException(); } public String getAuthType() { return null; } public String getContextPath() { return null; } public Cookie[] getCookies() { return null; } public long getDateHeader(String arg0) { return 0; } public String getHeader(String arg0) { return null; } public Enumeration getHeaderNames() { return null; } public Enumeration getHeaders(String arg0) { return null; } public int getIntHeader(String arg0) { return 0; } public String getMethod() { return null; } public String getPathInfo() { return pathInfo; } public String getPathTranslated() { return null; } public String getQueryString() { return null; } public String getRemoteUser() { return null; } public String getRequestedSessionId() { return null; } public String getRequestURI() { return null; } public StringBuffer getRequestURL() { return null; } public String getServletPath() { return null; } public HttpSession getSession() { return getSession(true); } public HttpSession getSession(boolean arg0) { if(session == null && arg0) session = new MockSession(); return session; } public Principal getUserPrincipal() { return null; } public boolean isRequestedSessionIdFromCookie() { return false; } /** * @deprecated */ public boolean isRequestedSessionIdFromUrl() { return false; } public boolean isRequestedSessionIdFromURL() { return false; } public boolean isRequestedSessionIdValid() { return false; } public boolean isUserInRole(String arg0) { return false; } public Object getAttribute(String arg0) { return null; } public Enumeration getAttributeNames() { return null; } public String getCharacterEncoding() { return null; } public int getContentLength() { return 0; } public String getContentType() { return null; } public ServletInputStream getInputStream() { return null; } public Locale getLocale() { return Locale.getDefault(); } public Enumeration getLocales() { return null; } public String getParameter(String arg0) { return null; } public Map getParameterMap() { return null; } public Enumeration getParameterNames() { return null; } public String[] getParameterValues(String arg0) { return null; } public String getProtocol() { return null; } public BufferedReader getReader() { return null; } /** * @deprecated */ public String getRealPath(String arg0) { return null; } public String getRemoteAddr() { return null; } public String getRemoteHost() { return null; } public RequestDispatcher getRequestDispatcher(String arg0) { return null; } public String getScheme() { return null; } public String getServerName() { return null; } public int getServerPort() { return 0; } public boolean isSecure() { return false; } public void removeAttribute(String arg0) { } public void setAttribute(String arg0, Object arg1) { } public void setCharacterEncoding(String arg0) { } } private static final class MockResponse implements HttpServletResponse { private final StringWriter writer = new StringWriter(); private final PrintWriter pwriter = new PrintWriter(writer); public void addCookie(Cookie arg0) { } public void addDateHeader(String arg0, long arg1) { } public void addHeader(String arg0, String arg1) { } public void addIntHeader(String arg0, int arg1) { } public boolean containsHeader(String arg0) { return false; } public void setCharacterEncoding(String arg0) { throw new UnsupportedOperationException(); } public String getContentType() { throw new UnsupportedOperationException(); } /** * @deprecated */ public String encodeRedirectUrl(String arg0) { return null; } public String encodeRedirectURL(String arg0) { return null; } /** * @deprecated */ public String encodeUrl(String arg0) { return null; } public String encodeURL(String arg0) { return null; } public void sendError(int arg0, String arg1) { } public void sendError(int arg0) { } public void sendRedirect(String arg0) { } public void setDateHeader(String arg0, long arg1) { } public void setHeader(String arg0, String arg1) { } public void setIntHeader(String arg0, int arg1) { } /** * @deprecated */ public void setStatus(int arg0, String arg1) { } public void setStatus(int arg0) { } public void flushBuffer() { } public int getBufferSize() { return 0; } public String getCharacterEncoding() { return null; } public Locale getLocale() { return null; } public ServletOutputStream getOutputStream() { return null; } public PrintWriter getWriter() { return pwriter; } public boolean isCommitted() { return false; } public void reset() { } public void resetBuffer() { } public void setBufferSize(int arg0) { } public void setContentLength(int arg0) { } public void setContentType(String arg0) { } public void setLocale(Locale arg0) { } public String toString() { pwriter.flush(); return writer.toString(); } } private static final class MockSession implements HttpSession { public Object getAttribute(String arg0) { return null; } public Enumeration getAttributeNames() { return null; } public long getCreationTime() { return 0; } public String getId() { return null; } public long getLastAccessedTime() { return 0; } public int getMaxInactiveInterval() { return 0; } public ServletContext getServletContext() { return null; } /** * @deprecated */ public HttpSessionContext getSessionContext() { return null; } /** * @deprecated */ public Object getValue(String arg0) { return null; } /** * @deprecated */ public String[] getValueNames() { return null; } public void invalidate() { } public boolean isNew() { return false; } /** * @deprecated */ public void putValue(String arg0, Object arg1) { } public void removeAttribute(String arg0) { } /** * @deprecated */ public void removeValue(String arg0) { } public void setAttribute(String arg0, Object arg1) { } public void setMaxInactiveInterval(int arg0) { } } /** Bootstrap for the self-test code. */ public static void main( String[] argc ) throws Exception { TestCase test = new TestJspTaglibs( "test-jsptaglibs.txt" ); test.run(); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/TestTag.java0000644000175000017500000001141311723544471026450 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.servlets; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTag; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.servlet.jsp.tagext.IterationTag; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TryCatchFinally; /** * @version $Id: TestTag.java,v 1.6 2003/01/12 23:40:26 revusky Exp $ * @author Attila Szegedi */ public class TestTag extends BodyTagSupport implements TryCatchFinally { private boolean throwException; private int repeatCount; public void setRepeatCount(int repeatCount) { this.repeatCount = repeatCount; } public void setThrowException(boolean throwException) { this.throwException = throwException; } public int doStartTag() throws JspException { try { pageContext.getOut().println("doStartTag() called here"); if(throwException) { throw new JspException("throwException==true"); } return repeatCount == 0 ? Tag.SKIP_BODY : BodyTag.EVAL_BODY_BUFFERED; } catch(IOException e) { throw new JspException(e); } } public int doAfterBody() throws JspException { try { getPreviousOut().println("doAfterBody() called here"); getBodyContent().writeOut(getPreviousOut()); getBodyContent().clear(); return --repeatCount == 0 ? Tag.SKIP_BODY : IterationTag.EVAL_BODY_AGAIN; } catch(IOException e) { throw new JspException(e); } } public int doEndTag() throws JspException { try { pageContext.getOut().println("doEndTag() called here"); return Tag.EVAL_PAGE; } catch(IOException e) { throw new JspException(e); } } public void doCatch(Throwable t) throws Throwable { pageContext.getOut().println("doCatch() called here with " + t.getClass() + ": " + t.getMessage()); } public void doFinally() { try { pageContext.getOut().println("doFinally() called here"); } catch(IOException e) { throw new Error(); // Shouldn't happen } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/WEB-INF/0000755000175000017500000000000012164627123025255 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/WEB-INF/web.xml0000644000175000017500000000105711723544471026563 0ustar ebourgebourg http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-2.2 /WEB-INF/fmtesttag.tld http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-2.2-2 /WEB-INF/taglib2.jar libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/WEB-INF/lib/0000755000175000017500000000000012164627123026023 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/WEB-INF/fmtesttag2.tld0000644000175000017500000000102611723544470030044 0ustar ebourgebourg 2.0 1.2 FreeMarker JUnit Test Support http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-autodeploy-tld simpletag freemarker.testcase.servlets.TestSimpleTag2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/WEB-INF/fmtesttag.tld0000644000175000017500000000104611723544471027765 0ustar ebourgebourg 2.0 1.2 FreeMarker JUnit Test Support testtag freemarker.testcase.servlets.TestTag simpletag freemarker.testcase.servlets.TestSimpleTag libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/TestSimpleTag.java0000644000175000017500000000203211723544471027617 0ustar ebourgebourgpackage freemarker.testcase.servlets; import java.io.IOException; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class TestSimpleTag extends SimpleTagSupport { private int bodyLoopCount = 1; private String name; public void setName(String name) { this.name = name; } public void setBodyLoopCount(int bodyLoopCount) { this.bodyLoopCount = bodyLoopCount; } public void doTag() throws JspException, IOException { JspContext ctx = getJspContext(); JspWriter w = ctx.getOut(); w.println("enter TestSimpleTag " + name); JspFragment f = getJspBody(); for(int i = 0; i < bodyLoopCount; ++i) { w.println("invoking body i=" + i); f.invoke(w); } w.println("exit TestSimpleTag " + name); } }libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/TestTag2.java0000644000175000017500000000663211723544467026546 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.servlets; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; /** * @version $Id: TestTag2.java,v 1.4 2003/01/12 23:40:26 revusky Exp $ * @author Attila Szegedi */ public class TestTag2 extends TagSupport { public int doStartTag() throws JspException { try { pageContext.getOut().println("TestTag2.doStartTag() called here"); return Tag.EVAL_BODY_INCLUDE; } catch(IOException e) { throw new JspException(e); } } public int doEndTag() throws JspException { try { pageContext.getOut().println("TestTag2.doEndTag() called here"); return Tag.EVAL_PAGE; } catch(IOException e) { throw new JspException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/TestSimpleTag2.java0000644000175000017500000000055511723544471027711 0ustar ebourgebourgpackage freemarker.testcase.servlets; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.SimpleTagSupport; public class TestSimpleTag2 extends SimpleTagSupport { public void doTag() throws JspException, IOException { getJspContext().getOut().println("Executed TestSimpleTag2"); } }libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/template/0000755000175000017500000000000012164627123026041 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/template/test-jsptaglibs.txt0000644000175000017500000000303711723544470031727 0ustar ebourgebourg<#assign tl = JspTaglibs["http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-2.2"]> <@tl.testtag repeatCount=3 throwException=false >Blah <@tl.testtag repeatCount=0 throwException=false >Blah <@tl.testtag repeatCount=0 throwException=true >Blah <@tl.testtag repeatCount=2 throwException=false >Outer Blah <@tl.testtag repeatCount=2 throwException=false >Inner Blah <@tl.testtag repeatCount=2 throwException=false> Outer Blah <@compress> <@tl.testtag repeatCount=2 throwException=false> Inner Blah <@tl.simpletag bodyLoopCount=2 name="simpletag1"> foo <@tl.simpletag bodyLoopCount=3 name="simpletag2"> bar <#assign tl2 = JspTaglibs["http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-2.2-2"]> <@tl2.testtag> <#assign tl3 = JspTaglibs["http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-2.2-foo"]> <@tl3.testtag> <#assign tl4 = JspTaglibs["/WEB-INF/taglib2.jar"]> <@tl4.testtag> <#assign tl5 = JspTaglibs["WEB-INF/taglib2.jar"]> <@tl5.testtag> <#assign tl6 = JspTaglibs["http://freemarker.sf.net/taglibs/freemarker-junit-test-tag-autodeploy-tld"]> <@tl6.simpletag/>libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/reference/0000755000175000017500000000000012164627123026164 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/reference/test-jsptaglibs.txt0000644000175000017500000000441611723544470032054 0ustar ebourgebourg doStartTag() called here doAfterBody() called here Blah doAfterBody() called here Blah doAfterBody() called here Blah doEndTag() called here doFinally() called here doStartTag() called here doEndTag() called here doFinally() called here doStartTag() called here doCatch() called here with class freemarker.template.TemplateModelException: throwException==true doFinally() called here doStartTag() called here doAfterBody() called here Outer Blah doStartTag() called here doAfterBody() called here Inner Blah doAfterBody() called here Inner Blah doEndTag() called here doFinally() called here doAfterBody() called here Outer Blah doStartTag() called here doAfterBody() called here Inner Blah doAfterBody() called here Inner Blah doEndTag() called here doFinally() called here doEndTag() called here doFinally() called here doStartTag() called here doAfterBody() called here Outer Blah doStartTag() called here doAfterBody() called here Inner Blah doAfterBody() called here Inner Blah doEndTag() called here doFinally() called heredoAfterBody() called here Outer Blah doStartTag() called here doAfterBody() called here Inner Blah doAfterBody() called here Inner Blah doEndTag() called here doFinally() called heredoEndTag() called here doFinally() called here enter TestSimpleTag simpletag1 invoking body i=0 foo enter TestSimpleTag simpletag2 invoking body i=0 bar invoking body i=1 bar invoking body i=2 bar exit TestSimpleTag simpletag2 invoking body i=1 foo enter TestSimpleTag simpletag2 invoking body i=0 bar invoking body i=1 bar invoking body i=2 bar exit TestSimpleTag simpletag2 exit TestSimpleTag simpletag1 TestTag2.doStartTag() called here TestTag2.doEndTag() called here TestTag3.doStartTag() called here TestTag3.doEndTag() called here TestTag2.doStartTag() called here TestTag2.doEndTag() called here TestTag2.doStartTag() called here TestTag2.doEndTag() called here Executed TestSimpleTag2libfreemarker-java-2.3.19.orig/src/freemarker/testcase/servlets/TestTag3.java0000644000175000017500000000663211723544470026541 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.servlets; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; /** * @version $Id: TestTag3.java,v 1.4 2003/01/12 23:40:26 revusky Exp $ * @author Attila Szegedi */ public class TestTag3 extends TagSupport { public int doStartTag() throws JspException { try { pageContext.getOut().println("TestTag3.doStartTag() called here"); return Tag.EVAL_BODY_INCLUDE; } catch(IOException e) { throw new JspException(e); } } public int doEndTag() throws JspException { try { pageContext.getOut().println("TestTag3.doEndTag() called here"); return Tag.EVAL_PAGE; } catch(IOException e) { throw new JspException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/test-xmlfragment.xml0000644000175000017500000000011111723544471026377 0ustar ebourgebourgC<>&"']]>libfreemarker-java-2.3.19.orig/src/freemarker/testcase/test-defaultxmlns1.xml0000644000175000017500000000023211723544470026645 0ustar ebourgebourg No NS x NS y NS x NS libfreemarker-java-2.3.19.orig/src/freemarker/testcase/PerformanceTest.fm0000644000175000017500000000011411723544471026004 0ustar ebourgebourg ${j["" + i]} #{k(i)} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/0000755000175000017500000000000012164627123023642 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/EnumTestClass.java0000644000175000017500000000562111723544470027246 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; /** * @author Attila Szegedi * @version $Id: EnumTestClass.java,v 1.1 2005/11/03 08:49:19 szegedia Exp $ */ public enum EnumTestClass { ONE, TWO, THREE; @Override public String toString() { return name() + "x"; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BeanTestClass.java0000644000175000017500000000675011723544470027213 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; /** * @author Attila Szegedi, szegedia at freemail dot hu * @version $Id: BeanTestClass.java,v 1.6 2003/01/12 23:40:25 revusky Exp $ */ public class BeanTestClass extends BeanTestSuperclass implements BeanTestInterface { public static final String STATIC_FINAL_FIELD = "static-final-field"; public static String STATIC_FIELD = "static-field"; public String getFoo() { return "foo-value"; } public String getBar(int index) { return "bar-value-" + index; } public String overloaded(int i) { return "overloaded-int-" + i; } public String overloaded(String s) { return "overloaded-String-" + s; } public static String staticMethod() { return "static-method"; } public static String staticOverloaded(int i) { return "static-overloaded-int-" + i; } public static String staticOverloaded(String s) { return "static-overloaded-String-" + s; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/TransformHashWrapper.java0000644000175000017500000000772011723544471030637 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; import freemarker.template.utility.*; /** * Part of the TestTransform testcase suite. * * @version $Id: TransformHashWrapper.java,v 1.15 2005/06/16 18:13:59 ddekany Exp $ */ public class TransformHashWrapper implements TemplateHashModel, TemplateScalarModel { private SimpleHash m_cHashModel = new SimpleHash(); /** Creates new TransformHashWrapper */ public TransformHashWrapper() { m_cHashModel.put( "htmlEscape", new HtmlEscape() ); m_cHashModel.put( "compress", new StandardCompress() ); m_cHashModel.put( "escape", new TransformMethodWrapper1() ); m_cHashModel.put( "special", new TransformMethodWrapper2() ); } /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) throws TemplateModelException { return m_cHashModel.get( key ); } /** * @return true if this object is empty. */ public boolean isEmpty() { return false; } /** * Returns the scalar's value as a String. * @return the String value of this scalar. */ public String getAsString() { return "Utility transformations"; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/MultiModel3.java0000644000175000017500000000734611723544471026661 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Testcase to see how FreeMarker deals with multiple Template models. * * @version $Id: MultiModel3.java,v 1.14 2004/01/06 17:06:44 szegedia Exp $ */ public class MultiModel3 implements TemplateScalarModel, TemplateHashModel { /** * Returns the scalar's value as a String. * * @return the String value of this scalar. */ public String getAsString() { return "Model3 is alive!"; } /** * @return true if this object is empty. */ public boolean isEmpty() { return false; } /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) { if( key.equals( "selftest" )) { return new SimpleScalar( "Selftest from MultiModel3!" ); } else if( key.equals( "message" )) { return new SimpleScalar( "Hello world from MultiModel3!" ); } else { return null; } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/LegacyList.java0000644000175000017500000000741111723544471026554 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; import java.util.*; /** * A little bridge class that subclasses the new SimpleList * and still implements the deprecated TemplateListModel */ public class LegacyList extends SimpleSequence { private Iterator iterator; /** * Resets the cursor to the beginning of the list. */ public synchronized void rewind() { iterator = null; } /** * @return true if the cursor is at the beginning of the list. */ public synchronized boolean isRewound() { return (iterator == null); } /** * @return true if there is a next element. */ public synchronized boolean hasNext() { if (iterator == null) { iterator = list.listIterator(); } return iterator.hasNext(); } /** * @return the next element in the list. */ public synchronized TemplateModel next() throws TemplateModelException { if (iterator == null) { iterator = list.listIterator(); } if (iterator.hasNext()) { return (TemplateModel)iterator.next(); } else { throw new TemplateModelException("No more elements."); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/ExceptionModel.java0000644000175000017500000000612511723544470027433 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * A template that always throws an exception whenever we call getAsString() * * @version $Id: ExceptionModel.java,v 1.13 2003/01/12 23:40:25 revusky Exp $ */ public class ExceptionModel implements TemplateScalarModel { /** * Returns the scalar's value as a String. * * @return the String value of this scalar. */ public String getAsString () throws TemplateModelException { throw new TemplateModelException( "Throwing from ExceptionModel!" ); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/NewTestModel2.java0000644000175000017500000000636011723544472027153 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Testcase to see how FreeMarker's ?new built-in deals with constructors. * * @version $Id: NewTestModel.java,v 1.4 2003/01/12 23:40:25 revusky Exp $ */ public class NewTestModel2 implements TemplateScalarModel { private final String string; public NewTestModel2() { string = "default constructor"; } public NewTestModel2(String str) { string = str; } public NewTestModel2(long i) { string = Long.toString(i); } public NewTestModel2(Object o1, java.io.Serializable o2) { string = o1 + ":" + o2; } public String getAsString() { return string; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BooleanHash1.java0000644000175000017500000000712411723544471026761 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Tests the impact that the isEmpty() has on template hash models. * * @author Nicholas Cull * @version $Id: BooleanHash1.java,v 1.15 2004/01/06 17:06:44 szegedia Exp $ */ public class BooleanHash1 implements TemplateHashModel { /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) { if( key.equals( "temp" )) { return new SimpleScalar( "Hello, world." ); } else if( key.equals( "boolean" )) { return TemplateBooleanModel.FALSE; } else { return new SimpleScalar( "Just another key..." ); } } /** * @return true if this object is empty. */ public boolean isEmpty() { return true; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/MultiModel1.java0000644000175000017500000001207011723544471026645 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Testcase to see how FreeMarker deals with multiple Template models. * * @version $Id: MultiModel1.java,v 1.17 2004/01/06 17:06:44 szegedia Exp $ */ public class MultiModel1 implements TemplateHashModel, TemplateSequenceModel, TemplateScalarModel { private TemplateModel m_cSubModel = new MultiModel2(); private TemplateModel m_cListHashModel1 = new MultiModel4(); private TemplateModel m_cListHashModel2 = new MultiModel5(); private TemplateSequenceModel m_cListModel = new SimpleSequence(); private TemplateHashModel m_cHashModel = new SimpleHash(); /** Creates new MultiModel1 */ public MultiModel1() { for( int i = 0; i < 10; i++ ) { ((SimpleSequence)m_cListModel).add( "Model1 value: " + Integer.toString( i )); } ((SimpleSequence)m_cListModel).add( new MultiModel3() ); ((SimpleHash)m_cHashModel).put( "nested", new MultiModel3() ); } /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) { if( key.equals( "model2" )) { return m_cSubModel; } else if( key.equals( "modellist" )) { return m_cListModel; } else if( key.equals( "selftest" )) { return new SimpleScalar( "Selftest of a hash from MultiModel1" ); } else if( key.equals( "one" )) { return m_cListHashModel1; } else if( key.equals( "two" )) { return m_cListHashModel2; } else if( key.equals( "size" )) { return new SimpleScalar( "Nasty!" ); } else if( key.equals( "nesting1" )) { return m_cHashModel; } else { return null; } } /** * @return true if this object is empty. */ public boolean isEmpty() { return false; } /** * @return the specified index in the list */ public TemplateModel get(int i) throws TemplateModelException { return m_cListModel.get( i ); } /** * Returns the scalar's value as a String. * * @return the String value of this scalar. */ public String getAsString() { return "MultiModel1 as a string!"; } public int size() throws TemplateModelException { return m_cListModel.size(); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/MultiModel2.java0000644000175000017500000000724611723544471026657 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; import java.util.*; /** * Testcase to see how FreeMarker deals with multiple Template models. * * @version $Id: MultiModel2.java,v 1.15 2004/01/06 17:06:44 szegedia Exp $ */ public class MultiModel2 implements TemplateScalarModel, TemplateMethodModel { /** * Returns the scalar's value as a String. * * @return the String value of this scalar. */ public String getAsString() { return "Model2 is alive!"; } /** * Executes a method call. * * @param arguments a List of String objects containing the values * of the arguments passed to the method. * @return the TemplateModel produced by the method, or null. */ public Object exec(List arguments) { StringBuffer aResults = new StringBuffer( "Arguments are:
" ); Iterator iList = arguments.iterator(); while( iList.hasNext() ) { aResults.append( (String)iList.next() ); aResults.append( "
" ); } return new SimpleScalar( aResults.toString() ); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/TransformMethodWrapper1.java0000644000175000017500000000663511723544470031260 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import java.util.*; import freemarker.template.*; import freemarker.template.utility.*; /** * Simple test of the interaction between MethodModels and TransformModels. * * @version $Id: TransformMethodWrapper1.java,v 1.12 2004/01/06 17:06:44 szegedia Exp $ */ public class TransformMethodWrapper1 extends Object implements TemplateMethodModel { /** * Executes a method call. * * @param arguments a List of String objects containing * the values of the arguments passed to the method. * @return the TemplateModel produced by the method, or null. */ public Object exec(List arguments) { if(( arguments.size() > 0 ) && ( arguments.get( 0 ).toString().equals( "xml" ))) { return new XmlEscape(); } else { return new HtmlEscape(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/NewTestModel.java0000644000175000017500000000635311723544470027071 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Testcase to see how FreeMarker's ?new built-in deals with constructors. * * @version $Id: NewTestModel.java,v 1.4 2003/01/12 23:40:25 revusky Exp $ */ public class NewTestModel implements TemplateScalarModel { private final String string; public NewTestModel() { string = "default constructor"; } public NewTestModel(String str) { string = str; } public NewTestModel(long i) { string = Long.toString(i); } public NewTestModel(Object o1, java.io.Serializable o2) { string = o1 + ":" + o2; } public String getAsString() { return string; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/SimpleTestMethod.java0000644000175000017500000000672111723544471027751 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import java.util.List; import freemarker.template.*; /** * A simple method model used as a test bed. * * @version $Id: SimpleTestMethod.java,v 1.12 2004/01/06 17:06:44 szegedia Exp $ */ public class SimpleTestMethod implements TemplateMethodModel { /** * Executes a method call. * * @param arguments a List of String objects containing * the values of the arguments passed to the method. * @return the TemplateModel produced by the method, or null. */ public Object exec(List arguments) { if( arguments.size() == 0 ) { return new SimpleScalar( "Empty list provided" ); } else if( arguments.size() > 1 ) { return new SimpleScalar( "Argument size is: " + arguments.size() ); } else { return new SimpleScalar( "Single argument value is: " + arguments.get(0) ); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/TransformMethodWrapper2.java0000644000175000017500000000771311723544470031257 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import java.util.*; import freemarker.template.*; /** * Another test of the interaction between MethodModels and TransformModels. * * @version $Id: TransformMethodWrapper2.java,v 1.12 2004/01/06 17:06:44 szegedia Exp $ */ public class TransformMethodWrapper2 implements TemplateMethodModel { /** * Executes a method call. * * @param arguments a List of String objects containing * the values of the arguments passed to the method. * @return the TemplateModel produced by the method, or null. */ public Object exec(List arguments) { TransformModel1 cTransformer = new TransformModel1(); Iterator iArgument = arguments.iterator(); // Sets up properties of the Transform model based on the arguments // passed into this method while( iArgument.hasNext() ) { String aArgument = (String)iArgument.next(); if( aArgument.equals( "quote" )) { cTransformer.setQuotes( true ); } else if( aArgument.equals( "tag" )) { cTransformer.setTags( true ); } else if( aArgument.equals( "ampersand" )) { cTransformer.setAmpersands( true ); } else { cTransformer.setComment( aArgument ); } } // Now return the transform class. return cTransformer; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BeanTestInterface.java0000644000175000017500000000021011723544472030031 0ustar ebourgebourgpackage freemarker.testcase.models; public interface BeanTestInterface { T getSomething(); void setSomething(T s); } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/MultiModel5.java0000644000175000017500000000754411723544467026670 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Testcase to see how FreeMarker deals with multiple Template models. * * @version $Id: MultiModel5.java,v 1.12 2004/01/06 17:06:44 szegedia Exp $ */ public class MultiModel5 implements TemplateSequenceModel, TemplateHashModel { private LegacyList m_cList = new LegacyList(); /** Creates new MultiModel5 */ public MultiModel5() { m_cList.add( new SimpleScalar( "Dummy to make list non-empty" )); } /** * @return the specified index in the list */ public TemplateModel get(int i) throws TemplateModelException { return m_cList.get( i ); } /** * @return true if this object is empty. */ public boolean isEmpty() { return false; } public int size() { return m_cList.size(); } /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) { if( key.equals( "empty" )) { return new SimpleScalar( "Dummy hash value, for test purposes." ); } else { return null; } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BooleanList1.java0000644000175000017500000001023711723544470027007 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Model for testing the impact of isEmpty() on template list models. Every * other method simply delegates to a SimpleList model. * * @author Nicholas Cull * @version $Id: BooleanList1.java,v 1.16 2004/01/06 17:06:44 szegedia Exp $ */ public class BooleanList1 implements TemplateSequenceModel { private LegacyList cList; /** Creates new BooleanList1 */ public BooleanList1() { cList = new LegacyList(); cList.add( "false" ); cList.add( "0" ); cList.add(TemplateBooleanModel.FALSE); cList.add(TemplateBooleanModel.TRUE); cList.add(TemplateBooleanModel.TRUE); cList.add(TemplateBooleanModel.TRUE); cList.add(TemplateBooleanModel.FALSE); } /** * @return true if there is a next element. */ public boolean hasNext() { return cList.hasNext(); } /** * @return the next element in the list. */ public TemplateModel next() throws TemplateModelException { return cList.next(); } /** * @return true if the cursor is at the beginning of the list. */ public boolean isRewound() { return cList.isRewound(); } /** * @return the specified index in the list */ public TemplateModel get(int i) throws TemplateModelException { return cList.get(i); } /** * Resets the cursor to the beginning of the list. */ public void rewind() { cList.rewind(); } public int size() { return cList.size(); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BeanTestSuperclass.java0000644000175000017500000000032011723544470030255 0ustar ebourgebourgpackage freemarker.testcase.models; public class BeanTestSuperclass { public Integer getSomething() { return 42; } public void setSomething(Integer x) { } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/MultiModel4.java0000644000175000017500000000723311723544472026656 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Testcase to see how FreeMarker deals with multiple Template models. * * @version $Id: MultiModel4.java,v 1.13 2004/01/06 17:06:44 szegedia Exp $ */ public class MultiModel4 implements TemplateSequenceModel, TemplateHashModel { private LegacyList m_cList = new LegacyList(); /** * @return the specified index in the list */ public TemplateModel get(int i) throws TemplateModelException { return m_cList.get( i ); } /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) { if( key.equals( "size" )) { return new SimpleScalar( "Key size, not the listSize method." ); } else { return null; } } public int size() { return m_cList.size(); } public boolean isEmpty() { return size() == 0; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/TransformModel1.java0000644000175000017500000001670111723544471027533 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; import java.io.*; import java.util.Map; /** * A TemplateTransformModel that includes properties. These properties can be * set at model construction time, or, for the purposes of this demonstration, * can be passed in from a wrapper TemplateMethodModel. * * @version $Id: TransformModel1.java,v 1.21 2003/01/12 23:40:25 revusky Exp $ */ public class TransformModel1 implements TemplateTransformModel { private boolean m_bAmpersands = false; private boolean m_bQuotes = false; private boolean m_bTags = false; private String m_aComment = ""; private static final int READER_BUFFER_SIZE = 4096; public Writer getWriter(final Writer out, final Map args) { final StringBuffer buf = new StringBuffer(); return new Writer(out) { public void write(char cbuf[], int off, int len) { buf.append(cbuf, off, len); } public void flush() { } public void close() throws IOException { StringReader sr = new StringReader(buf.toString()); StringWriter sw = new StringWriter(); transform(sr, sw); out.write(sw.toString()); } }; } /** * Indicates whether we escape ampersands. This property can be set either * while the model is being constructed, or via a property passed in through * a TemplateMethodModel. */ public void setAmpersands( boolean bAmpersands ) { m_bAmpersands = bAmpersands; } /** * Indicates whether we escape quotes. This property can be set either * while the model is being constructed, or via a property passed in through * a TemplateMethodModel. */ public void setQuotes( boolean bQuotes ) { m_bQuotes = bQuotes; } /** * Indicates whether we escape tags. This property can be set either * while the model is being constructed, or via a property passed in through * a TemplateMethodModel. */ public void setTags( boolean bTags ) { m_bTags = bTags; } /** * Sets a comment for this transformation. This property can be set either * while the model is being constructed, or via a property passed in through * a TemplateMethodModel. */ public void setComment( String aComment ) { m_aComment = aComment; } /** * Performs a transformation/filter on FreeMarker output. * * @param source the input to be transformed * @param output the destination of the transformation */ public void transform(Reader source, Writer output) throws IOException { // Output the source, converting unsafe certain characters to their // equivalent entities. int n = 0; boolean bCommentSent = false; char[] aBuffer = new char[ READER_BUFFER_SIZE ]; int i = source.read( aBuffer ); while (i >= 0) { for ( int j = 0; j < i; j++ ) { char c = aBuffer[j]; switch (c) { case '&': if ( m_bAmpersands ) { output.write("&"); } else { output.write( c ); } break; case '<': if ( m_bTags ) { output.write("<"); } else { output.write( c ); } break; case '>': if ( m_bTags ) { output.write(">"); } else { output.write( c ); } break; case '"': if ( m_bQuotes ) { output.write("""); } else { output.write( c ); } break; case '\'': if ( m_bQuotes ) { output.write("'"); } else { output.write( c ); } break; case '*': if ( ! bCommentSent ) { output.write( m_aComment ); bCommentSent = true; } else { output.write( c ); } break; default: output.write(c); } n++; } i = source.read( aBuffer ); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BooleanHash2.java0000644000175000017500000000653011723544471026762 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Tests the impact that the isEmpty() has on template hash models. * * @author Nicholas Cull * @version $Id: BooleanHash2.java,v 1.12 2004/01/06 17:06:44 szegedia Exp $ */ public class BooleanHash2 implements TemplateHashModel { /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ public TemplateModel get(String key) { return null; } /** * @return true if this object is empty. */ public boolean isEmpty() { return false; } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/VarArgTestModel.java0000644000175000017500000000166311723544472027523 0ustar ebourgebourgpackage freemarker.testcase.models; import java.util.Date; public class VarArgTestModel { public int bar(Integer... xs) { int sum = 0; for (Integer x : xs) { if (x != null) { sum *= 100; sum += x; } } return sum; } public int bar2(int first, int... xs) { int sum = 0; for (int x : xs) { sum *= 100; sum += x; } return -(sum * 100 + first); } public int overloaded(int x, int y) { return x * 100 + y; } public int overloaded(int... xs) { int sum = 0; for (int x : xs) { sum *= 100; sum += x; } return -sum; } public String noVarArgs(String s, boolean b, int i, Date d) { return s + ", " + b + ", " + i + ", " + d.getTime(); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BeansTestResources.properties0000644000175000017500000000005211723544471031544 0ustar ebourgebourgmessage=Message format={0,date,yyyy-MM-dd}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/models/BooleanList2.java0000644000175000017500000000642411723544470027013 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase.models; import freemarker.template.*; /** * Model for testing list models. Every * other method simply delegates to a SimpleList model. * * @author Nicholas Cull * @version $Id: BooleanList2.java,v 1.12 2003/01/12 23:40:25 revusky Exp $ */ public class BooleanList2 implements TemplateSequenceModel { private LegacyList cList; /** Creates new BooleanList2 */ public BooleanList2() { cList = new LegacyList(); } /** * @return the specified index in the list */ public TemplateModel get(int i) throws TemplateModelException { return cList.get(i); } public int size() { return cList.size(); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/TemplateCacheTest.java0000644000175000017500000002015611723544471026571 0ustar ebourgebourgpackage freemarker.testcase; import java.io.IOException; import java.io.Reader; import java.util.Locale; import freemarker.cache.StringTemplateLoader; import freemarker.cache.StrongCacheStorage; import freemarker.cache.TemplateCache; import freemarker.cache.TemplateLoader; import freemarker.template.Configuration; import junit.framework.TestCase; public class TemplateCacheTest extends TestCase { public TemplateCacheTest(String name) { super(name); } public void testCachedException() throws Exception { MockTemplateLoader loader = new MockTemplateLoader(); TemplateCache cache = new TemplateCache(loader, new StrongCacheStorage()); cache.setDelay(1000L); loader.setThrowException(true); try { cache.getTemplate("t", Locale.getDefault(), "", true); fail(); } catch(IOException e) { assertEquals("mock IO exception", e.getMessage()); assertEquals(1, loader.getFindCount()); try { cache.getTemplate("t", Locale.getDefault(), "", true); fail(); } catch(IOException e2) { // Still 1 - returned cached exception assertEquals("There was an error loading the template on an " + "earlier attempt; it is attached as a cause", e2.getMessage()); assertSame(e, e2.getCause()); assertEquals(1, loader.getFindCount()); try { Thread.sleep(1100L); cache.getTemplate("t", Locale.getDefault(), "", true); fail(); } catch(IOException e3) { // Cache had to retest assertEquals("mock IO exception", e.getMessage()); assertEquals(2, loader.getFindCount()); } } } } public void testCachedNotFound() throws Exception { MockTemplateLoader loader = new MockTemplateLoader(); TemplateCache cache = new TemplateCache(loader, new StrongCacheStorage()); cache.setDelay(1000L); cache.setLocalizedLookup(false); assertNull(cache.getTemplate("t", Locale.getDefault(), "", true)); assertEquals(1, loader.getFindCount()); assertNull(cache.getTemplate("t", Locale.getDefault(), "", true)); // Still 1 - returned cached exception assertEquals(1, loader.getFindCount()); Thread.sleep(1100L); assertNull(cache.getTemplate("t", Locale.getDefault(), "", true)); // Cache had to retest assertEquals(2, loader.getFindCount()); } private static class MockTemplateLoader implements TemplateLoader { private boolean throwException; private int findCount; public void setThrowException(boolean throwException) { this.throwException = throwException; } public int getFindCount() { return findCount; } public void closeTemplateSource(Object templateSource) throws IOException { } public Object findTemplateSource(String name) throws IOException { ++findCount; if(throwException) { throw new IOException("mock IO exception"); } return null; } public long getLastModified(Object templateSource) { return 0; } public Reader getReader(Object templateSource, String encoding) throws IOException { return null; } } public void testManualRemovalPlain() throws IOException { Configuration cfg = new Configuration(); cfg.setCacheStorage(new StrongCacheStorage()); StringTemplateLoader loader = new StringTemplateLoader(); cfg.setTemplateLoader(loader); cfg.setTemplateUpdateDelay(Integer.MAX_VALUE); loader.putTemplate("1.ftl", "1 v1"); loader.putTemplate("2.ftl", "2 v1"); assertEquals("1 v1", cfg.getTemplate("1.ftl").toString()); assertEquals("2 v1", cfg.getTemplate("2.ftl").toString()); loader.putTemplate("1.ftl", "1 v2"); loader.putTemplate("2.ftl", "2 v2"); assertEquals("1 v1", cfg.getTemplate("1.ftl").toString()); // no change assertEquals("2 v1", cfg.getTemplate("2.ftl").toString()); // no change cfg.removeTemplateFromCache("1.ftl"); assertEquals("1 v2", cfg.getTemplate("1.ftl").toString()); // changed assertEquals("2 v1", cfg.getTemplate("2.ftl").toString()); cfg.removeTemplateFromCache("2.ftl"); assertEquals("1 v2", cfg.getTemplate("1.ftl").toString()); assertEquals("2 v2", cfg.getTemplate("2.ftl").toString()); // changed } public void testManualRemovalI18ed() throws IOException { Configuration cfg = new Configuration(); cfg.setCacheStorage(new StrongCacheStorage()); cfg.setLocale(Locale.US); StringTemplateLoader loader = new StringTemplateLoader(); cfg.setTemplateLoader(loader); cfg.setTemplateUpdateDelay(Integer.MAX_VALUE); loader.putTemplate("1_en_US.ftl", "1_en_US v1"); loader.putTemplate("1_en.ftl", "1_en v1"); loader.putTemplate("1.ftl", "1 v1"); assertEquals("1_en_US v1", cfg.getTemplate("1.ftl").toString()); assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString()); assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString()); loader.putTemplate("1_en_US.ftl", "1_en_US v2"); loader.putTemplate("1_en.ftl", "1_en v2"); loader.putTemplate("1.ftl", "1 v2"); assertEquals("1_en_US v1", cfg.getTemplate("1.ftl").toString()); assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString()); assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString()); cfg.removeTemplateFromCache("1.ftl"); assertEquals("1_en_US v2", cfg.getTemplate("1.ftl").toString()); assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString()); assertEquals("1 v1", cfg.getTemplate("1.ftl", Locale.GERMANY).toString()); assertEquals("1 v2", cfg.getTemplate("1.ftl", Locale.ITALY).toString()); cfg.removeTemplateFromCache("1.ftl", Locale.GERMANY); assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString()); assertEquals("1 v2", cfg.getTemplate("1.ftl", Locale.GERMANY).toString()); cfg.removeTemplateFromCache("1.ftl", Locale.CANADA); assertEquals("1_en v1", cfg.getTemplate("1.ftl", Locale.UK).toString()); cfg.removeTemplateFromCache("1.ftl", Locale.UK); assertEquals("1_en v2", cfg.getTemplate("1.ftl", Locale.UK).toString()); } public void testZeroUpdateDelay() throws IOException { Configuration cfg = new Configuration(); cfg.setLocale(Locale.US); cfg.setCacheStorage(new StrongCacheStorage()); StringTemplateLoader loader = new StringTemplateLoader(); cfg.setTemplateLoader(loader); cfg.setTemplateUpdateDelay(0); for (int i = 1; i <= 3; i++) { loader.putTemplate("t.ftl", "v" + i, i); assertEquals("v" + i, cfg.getTemplate("t.ftl").toString()); } loader.putTemplate("t.ftl", "v10", 10); assertEquals("v10", cfg.getTemplate("t.ftl").toString()); loader.putTemplate("t.ftl", "v11", 10); // same time stamp, different content assertEquals("v10", cfg.getTemplate("t.ftl").toString()); // still v10 assertEquals("v10", cfg.getTemplate("t.ftl").toString()); // still v10 } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/TreeView.java0000644000175000017500000000752511723544470024770 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.FileReader; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTree; import freemarker.template.Template; public class TreeView { static public void main(String[] args) { if (args.length == 0) { usage(); return; } String filename = args[0]; Template t = null; try { t = new Template(filename, new FileReader(filename)); } catch (Exception e) { e.printStackTrace(); return; } showTree(t); } static void showTree(Template t) { JTree tree = new JTree(t.getRootTreeNode()); JFrame jf = new JFrame(t.getName()); jf.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); JScrollPane scrollPane = new JScrollPane(tree); jf.getContentPane().add(scrollPane); jf.pack(); jf.show(); } static void usage() { System.err.println("little toy program to display a compiled template as a tree."); System.err.println("Usage: java freemarker.testcase.TreeView "); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/test-xml.xml0000644000175000017500000000055311723544471024665 0ustar ebourgebourg text1 text2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/TemplateTestSuite.java0000644000175000017500000001652211723544471026661 0ustar ebourgebourg/* * Copyright (c) 2005 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase; import java.io.File; import java.lang.reflect.Constructor; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import junit.framework.TestCase; import junit.framework.TestSuite; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import freemarker.ext.dom.NodeModel; /** * Test suite for FreeMarker. The suite conforms to interface expected by * JUnit. * * @version $Id: TemplateTestSuite.java,v 1.8 2005/06/11 15:18:26 revusky Exp $ */ public class TemplateTestSuite extends TestSuite { private Map configParams = new LinkedHashMap(); public static TestSuite suite() throws Exception { return new TemplateTestSuite(); } public TemplateTestSuite() throws Exception { NodeModel.useJaxenXPathSupport(); readConfig(); } void readConfig() throws Exception { java.net.URL url = TemplateTestSuite.class.getResource("testcases.xml"); File f = new File(url.getFile()); readConfig(f); } /** * Read the testcase configurations file and build up the test suite */ public void readConfig(File f) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //dbf.setValidating(true); DocumentBuilder db = dbf.newDocumentBuilder(); Document d = db.parse(f); Element root = d.getDocumentElement(); NodeList children = root.getChildNodes(); for (int i=0; i0) { Class cl = Class.forName(classname); Constructor cons = cl.getConstructor(new Class[] {String.class, String.class}); return (TestCase) cons.newInstance(new Object [] {name, filename}); } TemplateTestCase result = new TemplateTestCase(name, filename); for (Iterator it=configParams.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String key = entry.getKey().toString(); String value = entry.getValue().toString(); System.out.println("Setting " + key + " to " + value); result.setConfigParam(entry.getKey().toString(), entry.getValue().toString()); } NodeList configs = e.getElementsByTagName("config"); for (int i=0; i Test Book Ch1 p1.1 p1.2 p1.3 Ch2 p2.1 p2.2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/ExceptionTest.java0000644000175000017500000000337311723544467026037 0ustar ebourgebourgpackage freemarker.testcase; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.StringReader; import java.io.StringWriter; import java.util.Collections; import junit.framework.TestCase; import freemarker.core.ParseException; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; public class ExceptionTest extends TestCase { public ExceptionTest(String name) { super(name); } public void testParseExceptionSerializable() throws IOException, ClassNotFoundException { Configuration cfg = new Configuration(); try { new Template("", new StringReader("<@>"), cfg); fail(); } catch (ParseException e) { ByteArrayOutputStream out = new ByteArrayOutputStream(); new ObjectOutputStream(out).writeObject(e); new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject(); } } public void testTemplateErrorSerializable() throws IOException, ClassNotFoundException { Configuration cfg = new Configuration(); Template tmp = new Template("", new StringReader("${noSuchVar}"), cfg); try { tmp.process(Collections.EMPTY_MAP, new StringWriter()); fail(); } catch (TemplateException e) { ByteArrayOutputStream out = new ByteArrayOutputStream(); new ObjectOutputStream(out).writeObject(e); new ObjectInputStream(new ByteArrayInputStream(out.toByteArray())).readObject(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/PerformanceTest.java0000644000175000017500000001544211723544471026335 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.testcase; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.List; import java.util.Locale; import freemarker.template.Configuration; import freemarker.template.SimpleHash; import freemarker.template.Template; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; /** * This class executes a FreeMarker template repeatedly in an endless loop. * It is meant to run inside a profiler to identify potential bottlenecks. * It can process either into a local file, or into a special /dev/null * style output stream. * @version $Id: PerformanceTest.java,v 1.18 2004/11/28 12:58:34 ddekany Exp $ */ public class PerformanceTest { public static void main(String[] args) throws Exception { Configuration config = new Configuration(); // config.setDebugMode(false); config.setClassicCompatible(false); config.setClassForTemplateLoading(PerformanceTest.class, "/freemarker/testcase"); Template template = config.getTemplate("PerformanceTest.fm"); boolean toFile = args.length > 0 && args[0].equals("file"); File f = File.createTempFile("fmPerfTest", ".txt"); f.deleteOnExit(); OutputStream nullStream = new NullStream(); SimpleHash h = new SimpleHash(); h.put("ii", new TestSequence()); h.put("j", new TestHash()); h.put("k", new TestMethod()); for(;;) { OutputStream stream = toFile ? new BufferedOutputStream(new FileOutputStream(f)) : nullStream; Writer writer = new OutputStreamWriter(stream, "UTF-8"); try { template.process(h, writer); } finally { writer.close(); } } } private static class TestSequence implements TemplateCollectionModel { public TemplateModelIterator iterator() { return new TemplateModelIterator() { private int i = 0; public TemplateModel next() { return new TestI(i++); } public boolean hasNext() { return i < 1000; } }; }; } private static class TestHash implements TemplateHashModel, TemplateScalarModel { public TemplateModel get(String key) { return this; } public String getAsString() { return "j"; } public boolean isEmpty() { return false; } } private static class TestMethod implements TemplateMethodModelEx { public Object exec(List arguments) { return arguments.get(0); } } private static class TestI implements TemplateHashModel, TemplateNumberModel { private final int i; TestI(int i) { this.i = i; } public TemplateModel get(String key) { return (i & 1) == 1 ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } public String getAsString(Locale locale) { return Integer.toString(i); } public Number getAsNumber() { return new Integer(i); } public boolean isEmpty() { return false; } } private static class NullStream extends OutputStream { public void close() { } public void flush() { } public void write(byte[] arg0, int arg1, int arg2) { } public void write(byte[] arg0) { } public void write(int arg0) { } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/OptInTemplateClassResolverTest.java0000644000175000017500000001767111723544471031337 0ustar ebourgebourgpackage freemarker.testcase; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import freemarker.core.OptInTemplateClassResolver; import freemarker.core.TemplateClassResolver; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.utility.ObjectConstructor; public class OptInTemplateClassResolverTest extends TestCase { public OptInTemplateClassResolverTest(String name) { super(name); } private static final Set ALLOWED_CLASSES = new HashSet(); static { ALLOWED_CLASSES.add("java.lang.String"); ALLOWED_CLASSES.add("java.lang.Integer"); } private static final List TRUSTED_TEMPLATES = new ArrayList(); static { TRUSTED_TEMPLATES.add("lib/*"); TRUSTED_TEMPLATES.add("/include/*"); TRUSTED_TEMPLATES.add("trusted.ftl"); } private OptInTemplateClassResolver resolver = new OptInTemplateClassResolver( ALLOWED_CLASSES, TRUSTED_TEMPLATES); private Configuration dummyCfg = new Configuration(); private Template dummyTemp = Template.getPlainTextTemplate("foo.ftl", "", dummyCfg); public void testOptIn() throws TemplateException { assertEquals(String.class, resolver.resolve("java.lang.String", null, dummyTemp)); assertEquals(Integer.class, resolver.resolve("java.lang.Integer", null, dummyTemp)); try { resolver.resolve("java.lang.Long", null, dummyTemp); fail(); } catch (TemplateException e) { // good } } public void testTrusted() throws TemplateException { assertEquals(Long.class, resolver.resolve("java.lang.Long", null, Template.getPlainTextTemplate("lib/foo.ftl", "", dummyCfg))); assertEquals(String.class, resolver.resolve("java.lang.String", null, Template.getPlainTextTemplate("lib/foo.ftl", "", dummyCfg))); assertEquals(Long.class, resolver.resolve("java.lang.Long", null, Template.getPlainTextTemplate("/lib/foo.ftl", "", dummyCfg))); assertEquals(Long.class, resolver.resolve("java.lang.Long", null, Template.getPlainTextTemplate("include/foo.ftl", "", dummyCfg))); assertEquals(Long.class, resolver.resolve("java.lang.Long", null, Template.getPlainTextTemplate("trusted.ftl", "", dummyCfg))); assertEquals(Long.class, resolver.resolve("java.lang.Long", null, Template.getPlainTextTemplate("/trusted.ftl", "", dummyCfg))); try { assertEquals(Long.class, resolver.resolve(ObjectConstructor.class.getName(), null, Template.getPlainTextTemplate("trusted.ftl", "", dummyCfg))); fail(); } catch (TemplateException e) { // good } } public void testCraftedTrusted() throws TemplateException { testTrusted_checkFails("lib/../foo.ftl"); testTrusted_checkFails("lib\\..\\foo.ftl"); testTrusted_checkFails("lib\\../foo.ftl"); testTrusted_checkFails("lib/..\\foo.ftl"); testTrusted_checkFails("lib/.."); testTrusted_checkFails("lib%2f%2E%2e%5cfoo.ftl"); testTrusted_checkFails("/lib%5C%.%2e%2Efoo.ftl"); try { testTrusted_checkFails("lib/./foo.ftl"); fail(); } catch (AssertionFailedError e) { // good } try { testTrusted_checkFails("lib/foo..ftl"); fail(); } catch (AssertionFailedError e) { // good } try { testTrusted_checkFails("lib/%2e/foo.ftl"); fail(); } catch (AssertionFailedError e) { // good } } public void testTrusted_checkFails(String templateName) { try { resolver.resolve("java.lang.Long", null, Template.getPlainTextTemplate(templateName, "", dummyCfg)); fail(); } catch (TemplateException e) { // good } } public void testSettingParser() throws TemplateException { Configuration cfg = new Configuration(); cfg.setSetting("new_builtin_class_resolver", "trusted_templates: foo.ftl, \"lib/*\""); TemplateClassResolver res = cfg.getNewBuiltinClassResolver(); assertEquals(String.class, res.resolve("java.lang.String", null, Template.getPlainTextTemplate("foo.ftl", "", cfg))); assertEquals(String.class, res.resolve("java.lang.String", null, Template.getPlainTextTemplate("lib/bar.ftl", "", cfg))); try { res.resolve("java.lang.String", null, Template.getPlainTextTemplate("bar.ftl", "", cfg)); fail(); } catch (TemplateException e) { // good } cfg.setSetting("new_builtin_class_resolver", "allowed_classes: java.lang.String, java.lang.Integer"); res = cfg.getNewBuiltinClassResolver(); assertEquals(String.class, res.resolve("java.lang.String", null, Template.getPlainTextTemplate("foo.ftl", "", cfg))); assertEquals(Integer.class, res.resolve("java.lang.Integer", null, Template.getPlainTextTemplate("foo.ftl", "", cfg))); try { res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("foo.ftl", "", cfg)); fail(); } catch (TemplateException e) { // good } cfg.setSetting("new_builtin_class_resolver", "trusted_templates: foo.ftl, 'lib/*', " + "allowed_classes: 'java.lang.String', java.lang.Integer"); res = cfg.getNewBuiltinClassResolver(); assertEquals(String.class, res.resolve("java.lang.String", null, Template.getPlainTextTemplate("x.ftl", "", cfg))); assertEquals(Integer.class, res.resolve("java.lang.Integer", null, Template.getPlainTextTemplate("x.ftl", "", cfg))); try { res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("x.ftl", "", cfg)); fail(); } catch (TemplateException e) { // good } assertEquals(Long.class, res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("foo.ftl", "", cfg))); assertEquals(Long.class, res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("lib/bar.ftl", "", cfg))); try { res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("x.ftl", "", cfg)); fail(); } catch (TemplateException e) { // good } try { cfg.setSetting("new_builtin_class_resolver", "wrong: foo"); fail(); } catch (TemplateException e) { // good } cfg.setSetting("new_builtin_class_resolver", "\"allowed_classes\" : java.lang.String , " + "'trusted_templates' :\"lib:*\""); res = cfg.getNewBuiltinClassResolver(); assertEquals(String.class, res.resolve("java.lang.String", null, Template.getPlainTextTemplate("x.ftl", "", cfg))); try { res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("x.ftl", "", cfg)); fail(); } catch (TemplateException e) { // good } assertEquals(Long.class, res.resolve("java.lang.Long", null, Template.getPlainTextTemplate("lib:bar.ftl", "", cfg))); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/StringUtilTest.java0000644000175000017500000000417411723544471026200 0ustar ebourgebourgpackage freemarker.testcase; import freemarker.template.utility.StringUtil; import junit.framework.TestCase; public class StringUtilTest extends TestCase { public StringUtilTest(String name) { super(name); } public void testJQuote() { assertEquals("null", StringUtil.jQuote(null)); assertEquals("\"foo\"", StringUtil.jQuote("foo")); assertEquals("\"123\"", StringUtil.jQuote(Integer.valueOf(123))); assertEquals("\"foo's \\\"bar\\\"\"", StringUtil.jQuote("foo's \"bar\"")); assertEquals("\"\\n\\r\\t\\u0001\"", StringUtil.jQuote("\n\r\t\u0001")); assertEquals("\"<\\nb\\rc\\td\\u0001>\"", StringUtil.jQuote("<\nb\rc\td\u0001>")); } public void testJQuoteNoXSS() { assertEquals("null", StringUtil.jQuoteNoXSS(null)); assertEquals("\"foo\"", StringUtil.jQuoteNoXSS("foo")); assertEquals("\"123\"", StringUtil.jQuoteNoXSS(Integer.valueOf(123))); assertEquals("\"foo's \\\"bar\\\"\"", StringUtil.jQuoteNoXSS("foo's \"bar\"")); assertEquals("\"\\n\\r\\t\\u0001\"", StringUtil.jQuoteNoXSS("\n\r\t\u0001")); assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"", StringUtil.jQuoteNoXSS("<\nb\rc\td\u0001>")); assertEquals("\"\\u003C\\nb\\rc\\td\\u0001>\"", StringUtil.jQuoteNoXSS((Object) "<\nb\rc\td\u0001>")); } public void testVersionStringToNumber() { assertEquals(1000000, StringUtil.versionStringToInt("1")); assertEquals(1002000, StringUtil.versionStringToInt("1.2")); assertEquals(1002003, StringUtil.versionStringToInt("1.2.3")); assertEquals(1002003, StringUtil.versionStringToInt("01.02.03")); assertEquals(12034056, StringUtil.versionStringToInt("12.34.56")); assertEquals(1000003, StringUtil.versionStringToInt("1.0.3rc4")); try { StringUtil.versionStringToInt("x"); fail(); } catch (IllegalArgumentException e) { // nop } } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/TagSyntaxVariationsTest.java0000644000175000017500000002222011723544470030045 0ustar ebourgebourgpackage freemarker.testcase; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import freemarker.core.ParseException; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.utility.StringUtil; import junit.framework.TestCase; /** * Test various generated templates (permutations), including some deliberately * wrong ones, with various tag_syntax settings. */ public class TagSyntaxVariationsTest extends TestCase { private static final String HDR_ANG = "<#ftl>"; private static final String HDR_SQU = squarify(HDR_ANG); private static final String IF_ANG = "<#if true>i"; private static final String IF_SQU = squarify(IF_ANG); private static final String IF_OUT = "i"; private static final String ASSIGN_ANG = "<#assign x = 1>a"; private static final String ASSIGN_SQU = squarify(ASSIGN_ANG); private static final String ASSIGN_OUT = "a"; private static final String WRONG_ANG = "<#wrong>"; private static final String WRONG_SQU = squarify(WRONG_ANG); private static final String WRONGC_ANG = ""; private static final String WRONGC_SQU = squarify(WRONGC_ANG ); private static final String CUST_ANG = "<@compress> z "; private static final String CUST_SQU = squarify(CUST_ANG); private static final String CUST_OUT = "z"; public TagSyntaxVariationsTest(String name) { super(name); } private static String squarify(String s) { return s.replace('<', '[').replace('>', ']'); } public final void test() throws TemplateException, IOException { Configuration cfgBuggy = new Configuration(); // Default on 2.3.x: cfgBuggy.setEmulate23ParserBugs(true); // Default on 2.3.x: cfgBuggy.setTagSyntax(Configuration.ANGLE_BRACKET_TAG_SYNTAX); Configuration cfgFixed = new Configuration(); cfgFixed.setIncompatibleEnhancements("2.3.19"); // Default on 2.3.x: cfgFixed.setTagSyntax(Configuration.ANGLE_BRACKET_TAG_SYNTAX); // Permutations for (int ifOrAssign = 0; ifOrAssign < 2; ifOrAssign++) { String dir_ang = ifOrAssign == 0 ? IF_ANG : ASSIGN_ANG; String dir_squ = ifOrAssign == 0 ? IF_SQU : ASSIGN_SQU; String dir_out = ifOrAssign == 0 ? IF_OUT : ASSIGN_OUT; // Permutations for (int angOrSqu = 0; angOrSqu < 2; angOrSqu++) { cfgBuggy.setTagSyntax(angOrSqu == 0 ? Configuration.ANGLE_BRACKET_TAG_SYNTAX : Configuration.SQUARE_BRACKET_TAG_SYNTAX); cfgFixed.setTagSyntax(angOrSqu == 0 ? Configuration.ANGLE_BRACKET_TAG_SYNTAX : Configuration.SQUARE_BRACKET_TAG_SYNTAX); String dir_xxx = angOrSqu == 0 ? dir_ang : dir_squ; String cust_xxx = angOrSqu == 0 ? CUST_ANG : CUST_SQU; String hdr_xxx = angOrSqu == 0 ? HDR_ANG : HDR_SQU; String wrong_xxx = angOrSqu == 0 ? WRONG_ANG : WRONG_SQU; String wrongc_xxx = angOrSqu == 0 ? WRONGC_ANG : WRONGC_SQU; test(cfgBuggy, dir_xxx + cust_xxx, dir_out + CUST_OUT); test(cfgFixed, dir_xxx + cust_xxx, dir_out + CUST_OUT); // Permutations for (int wrongOrWrongc = 0; wrongOrWrongc < 2; wrongOrWrongc++) { String wrongx_xxx = wrongOrWrongc == 0 ? wrong_xxx : wrongc_xxx; // Bug: initial unknown # tags are treated as static text test(cfgBuggy, wrongx_xxx + dir_xxx, wrongx_xxx + dir_out); test(cfgFixed, wrongx_xxx + dir_xxx, null); // Bug: same as above test(cfgBuggy, wrongx_xxx + wrongx_xxx + dir_xxx, wrongx_xxx + wrongx_xxx + dir_out); test(cfgBuggy, dir_xxx + wrongx_xxx, null); test(cfgFixed, dir_xxx + wrongx_xxx, null); test(cfgBuggy, hdr_xxx + wrongx_xxx, null); test(cfgFixed, hdr_xxx + wrongx_xxx, null); test(cfgBuggy, cust_xxx + wrongx_xxx + dir_xxx, null); test(cfgFixed, cust_xxx + wrongx_xxx + dir_xxx, null); } // for wrongc } // for squ cfgBuggy.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX); cfgFixed.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX); for (int perm = 0; perm < 4; perm++) { // All 4 permutations String wrong_xxx = (perm & 1) == 0 ? WRONG_ANG : WRONG_SQU; String dir_xxx = (perm & 2) == 0 ? dir_ang : dir_squ; // Bug: Auto-detection ignores unknown # tags test(cfgBuggy, wrong_xxx + dir_xxx, wrong_xxx + dir_out); test(cfgFixed, wrong_xxx + dir_xxx, null); // Bug: same as above test(cfgBuggy, wrong_xxx + wrong_xxx + dir_xxx, wrong_xxx + wrong_xxx + dir_out); } // for perm // Permutations for (int angOrSquStart = 0; angOrSquStart < 2; angOrSquStart++) { String hdr_xxx = angOrSquStart == 0 ? HDR_ANG : HDR_SQU; String cust_xxx = angOrSquStart == 0 ? CUST_ANG : CUST_SQU; String wrong_yyy = angOrSquStart != 0 ? WRONG_ANG : WRONG_SQU; String dir_xxx = angOrSquStart == 0 ? dir_ang : dir_squ; String dir_yyy = angOrSquStart != 0 ? dir_ang : dir_squ; test(cfgBuggy, cust_xxx + wrong_yyy + dir_xxx, CUST_OUT + wrong_yyy + dir_out); test(cfgFixed, cust_xxx + wrong_yyy + dir_xxx, CUST_OUT + wrong_yyy + dir_out); test(cfgBuggy, hdr_xxx + wrong_yyy + dir_xxx, wrong_yyy + dir_out); test(cfgFixed, hdr_xxx + wrong_yyy + dir_xxx, wrong_yyy + dir_out); test(cfgBuggy, cust_xxx + wrong_yyy + dir_yyy, CUST_OUT + wrong_yyy + dir_yyy); test(cfgFixed, cust_xxx + wrong_yyy + dir_yyy, CUST_OUT + wrong_yyy + dir_yyy); test(cfgBuggy, hdr_xxx + wrong_yyy + dir_yyy, wrong_yyy + dir_yyy); test(cfgFixed, hdr_xxx + wrong_yyy + dir_yyy, wrong_yyy + dir_yyy); test(cfgBuggy, dir_xxx + wrong_yyy + dir_yyy, dir_out + wrong_yyy + dir_yyy); test(cfgFixed, dir_xxx + wrong_yyy + dir_yyy, dir_out + wrong_yyy + dir_yyy); } // for squStart } // for assign } /** * @param expected the expected output or null if we expect * a parsing error. * @throws IOException * @throws TemplateException */ private static final void test( Configuration cfg, String template, String expected) throws TemplateException, IOException { Template t = null; try { t = new Template("string", new StringReader(template), cfg); } catch (ParseException e) { if (expected != null) { fail("Couldn't create Template from " + StringUtil.jQuote(template) + ": " + e); } else { return; } } if (expected == null) fail("Template parsing should have fail for " + StringUtil.jQuote(template)); StringWriter out = new StringWriter(); t.process(new Object(), out); assertEquals(expected, out.toString()); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/0000755000175000017500000000000012164627123024172 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-recover.ftl0000644000175000017500000000132111723544471027324 0ustar ebourgebourg<#attempt> <#assign sequence = ["Hello, World"]> ${sequence[0]} <#recover> We should never get here. <#attempt> Let's try to output an undefined variable: ${undefined} <#recover> Well, that did not work. Here is the error: ${.error} Now we nest another attempt/recover here: <#attempt> ${sequence[1]} <#recover> Oops: ${.error} Remember, freeMarker sequences are zero-based! ${sequence[0]} Now we output the current error message: ${.error} <#attempt> <#include "nonexistent_template"> <#recover> The template is not currently available <#attempt> <#include "undefined.ftl"> <#recover> The included template has a problem: ${.error} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-xmlns4.html0000644000175000017500000000150711723544470027270 0ustar ebourgebourg<#ftl ns_prefixes = {"x" : "http://x", "y" : "http://y"}> <#recurse doc > <#macro book> <#recurse .node["x:title"]>

<#recurse .node["x:title"]>

<#recurse> <#macro chapter>

<#recurse .node["y:title"]>

<#recurse> <#macro 'x:chapter'>

<#recurse .node["y:title"]>

<#recurse> <#macro para>

<#recurse> <#macro 'x:para'>

<#recurse> <#macro 'y:para'>

<#recurse> <#macro "x:title"> <#-- We have handled this element imperatively, so we do nothing here. --> <#macro "y:title"> <#-- We have handled this element imperatively, so we do nothing here. --> <#macro @text>${.node?html}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-wstrim.txt0000644000175000017500000000214111723544471027237 0ustar ebourgebourg LB<#lt> LB<#lt> LB<#lt> LB<#lt> IB IC1<#rt> IC2<#rt> C1<#rt> C2<#rt> ICS <#rt> CS1 <#rt> CS2 <#t> C3<#t> C1<#t> C2 B B C1<#t> CB C1 C2<#t> ICB IC<#rt> ICB IC<#rt> CB<#lt> -- <#macro x t>${t} ${""}<@x t="LB"/><#lt> <@x t="LB"/><#lt>${""} <@x t="LB"/><#lt>${""} <@x t="LB"/><#lt>${""} <@x t="IB"/>${""} ${""} <@x t="IC1"/><#rt> <@x t="IC2"/><#rt>${""} ${""}<@x t="C1"/><#rt> <@x t="C2"/><#rt>${""} <@x t="ICS"/> <#rt>${""} <@x t="CS1"/> <#rt>${""} <@x t="CS2"/> <#t>${""} <@x t="C3"/><#t> <@x t="C1"/><#t> <@x t="C2"/>${""} <#nt><@x t="B"/> <@x t="B"/><#nt> <@x t="C1"/><#t> <@x t="CB"/>${""} <@x t="C1"/>${""} <@x t="C2"/><#t>${""} <@x t="ICB"/>${""} ${""}<@x t="IC"/><#rt> <@x t="ICB"/>${""} ${""} <@x t="IC"/><#rt> <@x t="CB"/>${""}<#lt> -- <#lt> IB IC1<#rt> <#assign x = 1> <#-- just a comment --> C2<#t> <#assign x = 1> IB 1<#t> <#assign x = 1> 2 --- <#t>1 <#t> 2 <#lt>3 4 <#rt>5 6 --- a <#assign x = 1><#t> b<#t> c --- <#if true> <#t>foo --- <#if true><#-- just a comment --> foo<#t> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-stringbuiltins.txt0000644000175000017500000000474011723544470031000 0ustar ebourgebourgFreeMarker: Encoding string built-in tests <#assign x = r' dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} '> cap_first: ${x?cap_first} uncap_first:${x?uncap_first} uncap_first:${"Blah"?uncap_first} capitalize: ${x?capitalize} html: ${x?html} length: ${x?length} lower_case: ${x?lower_case} rtf: ${x?rtf} trim: ${x?trim} trim2: ${"foo bar"?trim} trim3: ${" foo bar"?trim} trim4: ${"foo bar "?trim} upper_case: ${x?upper_case} xml: ${x?xml} xhtml: ${('"' + "Blah's is > 1 & < 2" + '"')?xhtml} word_list: <#global words = x?word_list> <#foreach shortvariablenamesmakeyourcodemorereadable in words>- ${shortvariablenamesmakeyourcodemorereadable} <#global canufeelitbabe = x?interpret> interpret: <#transform canufeelitbabe> <#setting locale="es_ES">number: ${"-123.45"?number + 1.1} ${"freemarker.testcase.models.NewTestModel"?new()} ${"freemarker.testcase.models.NewTestModel"?new(1)} ${"freemarker.testcase.models.NewTestModel"?new("xxx")} ${"freemarker.testcase.models.NewTestModel"?new("xxx", "yyy")} <#assign x = "In the beginning, God created the Heavens and The Earth."> ${x?replace("the", "The Sacred, Holy", "i")} <#-- case insensitive replacement --> ${x?replace("the", "the very", "f")} <#-- replace only the first one --> ${x?replace("", "|")} <#-- replace empry string --> ${x?replace("", "|", "f")} <#-- replace first empty string --> ${x?replace("the H[a-z]+", "the sky", "r")} <#-- regexp replacement --> <#if x?matches(".*Heav..s.*")>matches<#else>Really? <#list x?matches("(the) ([a-z]+)", "i") as match> ${match} ${match?groups[1]} sacred ${match?groups[2]} <#assign matches = x?matches("In the ([a-z]+), God created (.*)")> ${matches?groups[0]} ${matches?groups[1]} ${matches?groups[2]} <#assign x="foo, bar;baz, foobar"> <#list x?split("[,;] ?", "r") as word> ${word} <#assign a = "foo", b="bar", c="(a+b)?upper_case"> ${c?eval} [${"a"?j_string}] = [a] [${"a\\'x'\nb"?j_string}] = [a\\'x'\nb] [${"\x1\x1A\x20"?j_string}] = [\u0001\u001a ] [${"a"?js_string}] = [a] [${"a\\'x'\nb"?js_string}] = [a\\\'x\'\nb] [${"\x1\x1A\x20"?js_string}] = [\x01\x1A ] [${"a"?json_string}] = [a] [${"a\\'x'\nb"?json_string}] = [a\\'x'\nb] [${"\x1\x1A\x20"?json_string}] = [\u0001\u001A ] [${"\n\r\t\f\b\""?json_string}] = [\n\r\t\f\b\"] [${"/"?json_string}] = [/] [${"a/b"?json_string}] = [a/b] [${""?json_string}] = [<\/script>] [${"]]>"?json_string}] = []]\u003E] libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-import.txt0000644000175000017500000000071311723544470027226 0ustar ebourgebourg-- <#-- import "/test-import_lib.txt" as my --> -- <#if mail?exists || test?exists> <#stop "mail or test should not exist"> ${my.mail} <@my.test foo="bar"/> <#assign mail="jsmith@other1.com"> ${my.mail} <@my.test foo="bar"/> <#assign mail in my> jsmith@other2.com<#t> ${my.mail} <@my.test foo="bar"/> <#import "/test-import_lib.txt" as my2> ${my2.mail} <#assign mail="jsmith@other3.com" in my2> ${my.mail} ${my2.doubleUp("foobar")}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-arithmetic.html0000644000175000017500000000077311723544471030201 0ustar ebourgebourg[#ftl] FreeMarker: Arithmetic Test [#assign foo = 1234, bar = 23.77]

A simple test follows:

Perform a number assignment:

[#setting locale="en_US"][#assign x = 1.2345, y=2] #{ x+y ; m2M3} #{ y ; m2M3} #{ x/y ; m40M40} #{y/x} #{ y/x ; M4}

Display a number with at least 3 digits after the decimal point

#{foo ; m3}

Now use numbers in assignment

[#assign mynumber = foo + bar [#-- a comment --] ] #{mynumber} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-included.html0000644000175000017500000000050311723544470027625 0ustar ebourgebourg

A test of included files:

<#if .globals.message?exists>

Message exists!:
${.globals.message}

<#else>

No message :(

<#assign foo="assigning from included template", bar=" Can you see me? "> <#macro twice><#nested/>${bar}<#nested/> <#include "nestedinclude.ftl"> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-encodingbuiltins.txt0000644000175000017500000000120711723544467031261 0ustar ebourgebourgFreeMarker: Encoding built-in tests <#assign x = "&<>\"'{}\\a/"> html: [${x?html}] xml: [${x?xml}] xhtml: [${x?xhtml}] rtf: [${x?rtf}] <#assign x = "a&aa\"a'a{a}a\\"> html: [${x?html}] xml: [${x?xml}] xhtml: [${x?xhtml}] rtf: [${x?rtf}] <#assign x = "<<<<<"> html: [${x?html}] xml: [${x?xml}] xhtml: [${x?xhtml}] <#assign x = "{{{{{"> rtf: [${x?rtf}] <#assign x = ""> html: [${x?html}] xml: [${x?xml}] xhtml: [${x?xhtml}] rtf: [${x?rtf}] <#assign x = "a"> html: [${x?html}] xml: [${x?xml}] xhtml: [${x?xhtml}] rtf: [${x?rtf}] <#assign x = "&"> html: [${x?html}] xml: [${x?xml}] xhtml: [${x?xhtml}] <#assign x = "{"> rtf: [${x?rtf}]libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-new-allowsnothing.txt0000644000175000017500000000014111723544467031374 0ustar ebourgebourg<#attempt> ${"freemarker.testcase.models.NewTestModel"?new("works")} <#recover> fails libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-exception.html0000644000175000017500000000023011723544470030031 0ustar ebourgebourg FreeMarker: Exception Test

A simple test follows:

${message}
${test}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-strictinheader_inc1.html0000644000175000017500000000005511723544471031763 0ustar ebourgebourg<#ftl strict_syntax="no"> ${x}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-stringbimethods.txt0000644000175000017500000000067711723544470031132 0ustar ebourgebourg<#setting locale="en_US"> <#assign x = 3> ${x?string["0.00"]} ${x?string("0.00")} --- ${multi} <#assign a = true> <#assign b = false> ${a?string} ${b?string} ${a?string("yes", "no")} ${b?string("yes", "no")} <#setting boolean_format="igen,nem"/> ${a?string} ${b?string} <#setting number_format="0.0"> ${a?string(0, 1)} ${b?string(0, 1)} <#setting boolean_format="true,false"/> ${a?string(0, 1)?is_string?string} ${b?string(0, 1)?is_string?string} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-xmlns3.html0000644000175000017500000000150711723544470027267 0ustar ebourgebourg<#ftl ns_prefixes = {"x" : "http://x", "y" : "http://y"}> <#recurse doc > <#macro book> <#recurse .node["x:title"]>

<#recurse .node["x:title"]>

<#recurse> <#macro chapter>

<#recurse .node["y:title"]>

<#recurse> <#macro "x:chapter">

<#recurse .node["y:title"]>

<#recurse> <#macro para>

<#recurse> <#macro "x:para">

<#recurse> <#macro "y:para">

<#recurse> <#macro "x:title"> <#-- We have handled this element imperatively, so we do nothing here. --> <#macro "y:title"> <#-- We have handled this element imperatively, so we do nothing here. --> <#macro @text>${.node?html}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-charsetinheader.html0000644000175000017500000000033611723544470031173 0ustar ebourgebourg<#ftl encoding="ISO-8859-2"> éáõû <#include "test-charsetinheader_inc1.html"> <#include "test-charsetinheader_inc2.html"> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-number-to-date.txt0000644000175000017500000000144111723544467030544 0ustar ebourgebourg${1305575275540?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z ${1305575275540?number_to_date?iso_utc} == 2011-05-16 ${1305575275540?number_to_time?iso_utc_ms} == 19:47:55.54Z ${1305575275540?long?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z ${1305575275540?double?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z ${bigInteger?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z ${bigDecimal?number_to_datetime?iso_utc_ms} == 2011-05-16T19:47:55.54Z ${1000?float?number_to_datetime?iso_utc} == 1970-01-01T00:00:01Z ${1000?int?number_to_datetime?iso_utc} == 1970-01-01T00:00:01Z ${0?byte?number_to_datetime?iso_utc} == 1970-01-01T00:00:00Z <#attempt> ${9999991305575275540?number_to_datetime?iso_utc} <#-- doesn't fit into long --> <#recover> failed libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-exception2.html0000644000175000017500000000023011723544470030113 0ustar ebourgebourg FreeMarker: Exception Test

A simple test follows:

${message}
${test}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-local_en_AU.html0000644000175000017500000000024111723544470030176 0ustar ebourgebourg FreeMarker: Localization Test

A simple test follows:

${message}

G'day, mate!

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-xml.html0000644000175000017500000000142711723544471026645 0ustar ebourgebourg<#-- test processing instructions --> <#global PIs = doc._content._ftype("p")> <#foreach pi in PIs> ${pi} ${pi["@target"]._text} ${pi["@data"]._text} ${PIs?size} <#global firstPi = PIs[0]> ${firstPi._type} ${firstPi["@customKey"]} ${doc._registerNamespace("ns", "http://www.foo.com/ns1/")} ${doc._descendant["ns:e11"]} ${doc._descendant["ns:e12"]} <#global docRoot = doc["ns:root"]> ${docRoot["ns:e1"]} ${doc("//ns:e11")} ${docRoot["ns:e1"]["@a1"]._name} ${docRoot["ns:e1"]["@a2"]._text} ${docRoot._children._parent._name} ${docRoot._children._parent._unique._name} <#foreach d in doc._descendant> ${d._name} <#foreach d in doc._descendant._ancestorOrSelf> ${d._name} ${docRoot["ns:e2"]["ns:e12"]._text} ${docRoot["ns:e2"]["ns:e12"]._plaintext} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-variables.html0000644000175000017500000000207611723544470030015 0ustar ebourgebourg[#ftl] FreeMarker: Variable Test [#assign list = ["one", "two", "three", "four", "five"]] [#assign hash = {"output" : "My message.", "key" : list}] [#assign hash2 = {"value" : hash}] [#assign items = {"mykey" : "key", "_test", "out"}]

A simple test follows:

${message}

Now get into variable nesting:

${hash.output}

${hash["output"]}

${hash. output}

${hash .output}

${hash .output}

${hash . output}

${hash ["output"]}

${hash [ "output" ]}

More deep nesting...

${hash2.value.output}

${hash2.value.key[0]}

${hash2["value"]["key"][0]}

Nesting inside nesting...

${hash2.value[ items.mykey ][ 1 ]}

${hash2.value[ items[ "mykey" ]][ 1 ]}

${hash2.value[ items[ "my" + items.mykey ]][ 1 ]}

${hash2.value[ items[ "my" + items["mykey"] ]][ 1 ]}

Test underscores...

${items[ "_test" ]}

${items._test}

${"God save the queen."?word_list[1]?upper_case} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-escapes.txt0000644000175000017500000000161211723544472027340 0ustar ebourgebourg<#assign h=["","a","b","c"]> <#assign g={"x":1,"y":2,"z":3}> <#escape x as h[x]> ${1} ${2} ${3} <#escape x as g[x]> ${"x"} ${"y"} ${"z"} <#noescape>${1} <#noescape><#noescape>${1} ${1} ${2} ${3} <#escape x as x?html> ${"<&>"} <#escape x as x?xml> ${"<&>"} ${"<&>"} --- <#assign x = ""> ${x} = <#escape x as x?upper_case> ${x} = <#escape x as x?html> ${x} = <MOOO> <#noescape> ${x} = ${x} = <MOOO> ${x} = <#noescape> ${x} = <#escape x as x?html> ${x} = <Mooo> <#noescape> ${x} = ${x} = <Mooo> ${x} = ${x} = <#escape az as ["red", "green", "blue"][az-1]> ${1} ${2} ${3} ---libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-switch.html0000644000175000017500000000152311723544470027342 0ustar ebourgebourg FreeMarker: Switch-Case Test

Here we iterate over a list of animals.

<#assign animalList = [ "aardvark", "kiwi", "gecko", "cat", "dog", "elephant", "squirrel", "zebra" ]> <#assign favoriteAnimal = "kiwi"> <#foreach animal in animalList>

Animal is: ${animal}.
<#switch animal> <#case "zebra"> This is the HTML for a large stripey animal. <#case "elephant"> <#case "rhinocerous"> This is the HTML for large animals. <#break> <#case "squirrel"> <#case "gecko"> This is the HTML for small animals. <#break> <#case favoriteAnimal> This is the HTML for the user's favorite animal. <#break> <#default> This is the HTML for other animals. <#break>

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-lastcharacter.html0000644000175000017500000000034611723544471030664 0ustar ebourgebourg FreeMarker: Last Character Test

A simple test follows:

#{message?capitalize?length} ${message [1..] ? upper_case} message: ${message ?capitalize[0..10]} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-varlayers.txt0000644000175000017500000000130311723544471027721 0ustar ebourgebourg<#import "test-varlayers_lib.txt" as lib> <@foo 1/> ${x} = ${.data_model.x} = ${.globals.x} <#assign x = 5> ${x} = ${.main.x} = ${.namespace.x} <#global x = 6> ${.globals.x} but ${.data_model.x} = 4 ${y} = ${.globals.y} = ${.data_model.y?default("ERROR")} Invisiblity test 1.: <#if .main.y?exists || .namespace.y?exists>failed<#else>passed Invisiblity test 2.: <#if .main.z?exists || .namespace.z?exists>failed<#else>passed Invisiblity test 3.: <#global q = 1><#if .main.q?exists || .namespace.q?exists || .data_model.q?exists>failed<#else>passed -- <@lib.foo/> -- <#macro foo x> ${x} = ${.locals.x} <#local x = 2> ${x} = ${.locals.x} <#local y = 3> ${y} = ${.locals.y} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-transformation.html0000644000175000017500000000531211723544470031107 0ustar ebourgebourg<#ftl strict_syntax=false> <#assign htmlEscape = "freemarker.template.utility.HtmlEscape"?new(), jython = "freemarker.template.utility.JythonRuntime"?new(), utility = "freemarker.testcase.models.TransformHashWrapper"?new()> FreeMarker: Transformation Test

A simple test follows:

${message}

<@htmlEscape>

${message}

Now try the Utility package:

${utility}

${utility}

Now some nested transforms:

This tests the compress transformation

<@utility.compress>

This tests the compress transformation

<#assign html_transform = "freemarker.template.utility.HtmlEscape"?new() /> <#--Using the transform via an instantiation -->

This tests the compress transformation

Now try method and transform interactions:

This isn't a valid XML string.

This isn't a valid HTML string.

A more advanced interaction involves getting a TemplateMethodModel to initialise a TemplateTransformModel, as follow:

Comment: * A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish & Chips.

Comment: * A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish & Chips.

Comment: * A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish & Chips.

Comment: * A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish & Chips.

<#assign captured_output> print 2+2 # Now we interact with the template environment somewhat. print ${x} + ${y} print env['x'] # using a variable from the template env["message"] = 'I saw the ${z}. It was ${adjective}.' ${message} ${captured_output} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/nestedinclude.ftl0000644000175000017500000000012211723544470027525 0ustar ebourgebourg<#assign nestedMessage = "I'm here, mon!"> ${.main.bar} <#-- ${.root.message} --> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-stringliteral.html0000644000175000017500000000203711723544470030725 0ustar ebourgebourg FreeMarker: String literal test

A simple test follows:

<#assign x = "Hello", y = "World"> <#assign message = "${x}, ${y}!"> ${message}

[${""}] = []
[${"a"}] = [a]
[${"abcdef"}] = [abcdef]
[${"\""}] = ["]
[${"\"\"\""}] = ["""]
[${"a\""}] = [a"]
[${"\"a"}] = ["a]
[${"a\"b"}] = [a"b]
[${"a\nb"}] = [a b]
[${"'"}] = [']
[${"a'a"}] = [a'a]
[${"\"\'\n\r\f\b\t\l\a\g"}]
[${"\xA\x0A\x00A\x000A\x0000A"}]
[${"\x15Bz\x15b"}]
[${"\x010Cz\x010c"}]

[${''}] = []
[${'a'}] = [a]
[${'abcdef'}] = [abcdef]
[${'"'}] = ["]
[${'"""'}] = ["""]
[${'a"'}] = [a"]
[${'"a'}] = ["a]
[${'a"b'}] = [a"b]
[${'a\nb'}] = [a b]
[${'\''}] = [']
[${'a\'a'}] = [a'a]
[${'\"\'\n\r\f\b\t\l\a\g'}]
[${'\xA\x0A\x00A\x000A\x0000A'}]
[${'\x15Bz\x15b'}]
[${'\x010Cz\x010c'}]
libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-hashconcat.ftl0000644000175000017500000000072211723544471027776 0ustar ebourgebourg[#ftl] [#assign a = {"a":1, "b":2, "c":3, "X": 4}] [#assign b = {"d":10, "e":20, "f":30, "X": 40}] a: [@dump a /] B: [@dump b /] a + B: [@dump a + b /] B + a: [@dump b + a /] a + a: [@dump a + a /] {} + a: [@dump {} + a /] a + {}: [@dump a + {} /] {} + {}: [@dump {} + {} /] a + b + {} + b + {} + a: [@dump a + b + {} + b + {} + a /] [#macro dump s] [#list s?keys as k] ${k} = ${s[k]} [/#list] --- [#list s?values as v] ${v} [/#list] --- [/#macro]libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-xmlns5.txt0000644000175000017500000000056711723544470027151 0ustar ebourgebourg<#ftl ns_prefixes = {"D": "http://y.com", "xx" : "http://x.com"}> <#assign r = doc["N:root"]> ${r["N:t1"][0]?default('-')} = No NS ${r["xx:t2"][0]?default('-')} = x NS ${r["t3"][0]?default('-')} = y NS ${r["xx:t4"][0]?default('-')} = x NS ${r["//t1"][0]?default('-')} = No NS ${r["//t2"][0]?default('-')} = - ${r["//t3"][0]?default('-')} = - ${r["//t4"][0]?default('-')} = - libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-numberformat.txt0000644000175000017500000000043011723544470030411 0ustar ebourgebourg<#setting number_format = ",##0.##"> <#setting locale = "fr_FR"> ${1} ${1?c} ${1234567.886} ${1234567.886?c} <#setting number_format = "0.00"> ${1} ${1?c} ${1234567.886} ${1234567.886?c} ${int?c} ${double?c} ${double2?c} ${double3?c} ${double4?c} ${bigDecimal?c} ${bigDecimal2?c} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-varlayers_lib.txt0000644000175000017500000000035111723544471030551 0ustar ebourgebourg<#assign x1 = .data_model.x> <#assign x2 = x> <#assign z2 = z> <#macro foo> <@.main.foo 1/> ${z} = ${z2} = ${x1} = ${.data_model.x} 5 ${x} == ${.globals.x} ${y} == ${.globals.y} == ${.data_model.y?default("ERROR")} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-newlines2.html0000644000175000017500000000046711723544471027756 0ustar ebourgebourg<#assign message="Hello, world!\n"> <#assign normalizeNewlines = "freemarker.template.utility.NormalizeNewlines"?new()> <#transform normalizeNewlines> FreeMarker: Newlines the Second Test

A simple test follows:

${message}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-listliteral.html0000644000175000017500000000230611723544471030372 0ustar ebourgebourg FreeMarker: List Literal Test

A simple test follows:

${message}

Now perform a list assignment:

<#assign hash = {"temp", "Temporary"}> <#assign mymessage = "hello"> <#assign test = [ "test1", "test23", "test45", message, mymessage]> The list contains #{test?size} items. <#foreach item in test>

${item}

Now update the assignment and repeat:

<#assign mymessage = "world"> <#foreach item in test>

${item}

Now reassign the list and repeat:

<#assign test = [ hash.temp, "test1", "test23", "test45", mymessage, "hash", hash["temp"]]> <#assign test = [ "foo", "bar" ] + test> <#foreach item in test[1..4]>

${item}

Silly, but necessary tests, for one and zero element lists:

<#assign test = [ "Hello, world" ]> <#foreach item in test>

${item}

Zero item test:

<#assign test = []> <#foreach item in test>

${item}

Dumb test for number literals -- these weren't working as expected:

<#assign test = [] + [1, 2,3, 5, 7]> <#foreach item in test>

${item}

<#if item == 5><#break> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-noparse.html0000644000175000017500000000150511723544470027510 0ustar ebourgebourg<#ftl strict_syntax=false> FreeMarker: NoParse Test A simple test follows: ${message} A more rigorous test, showing that we're not faking it: ${message@#$%&}

Message exists! ...and even generates output! Nested statements are ok, too.

Here's another edge case, this time, trying to output a <noparse> inside another <noparse> This is what the noparse instruction looks like: arse>This part of the template wont be parsed by the FreeMarker parser. Instead, it will be treated as verbatim text information, and output as such.arse> The rest of the template appears here. Simple. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-new-safer.txt0000644000175000017500000000026711723544470027607 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} <#attempt> ${"freemarker.template.utility.ObjectConstructor"?new()("java.lang.String", "works")} <#recover> fails libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-wsstripinheader.txt0000644000175000017500000000014111723544470031122 0ustar ebourgebourg <#ftl strip_whitespace="no"> a <#assign x = 1> b <#include "test-wsstripinheader_inc.txt">libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-newlines1.html0000644000175000017500000000020711723544470027744 0ustar ebourgebourg FreeMarker: Newlines Test

A simple test follows:

${message}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-xmlfragment.txt0000644000175000017500000000026611723544471030244 0ustar ebourgebourg<#ftl ns_prefixes = {"n" : "http://x"}> ${node?node_name} = b ${node?root?node_name} = @document ${node['/']?node_name} = @document ${node['n:c']} = C<>&"']]> ${node?root.@@markup}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-charsetinheader_inc1.html0000644000175000017500000000004211723544471032100 0ustar ebourgebourg<#ftl encoding="ISO-8859-1"> õÕûÛ libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-defaultxmlns1.txt0000644000175000017500000000041411723544471030502 0ustar ebourgebourg<#ftl ns_prefixes={"D" : "http://x.com", "y" : "http://y.com"}> <#assign r = doc.*[0]> ${r["N:t1"]?default('-')} = No NS ${r["t2"]?default('-')} = x NS ${r["y:t3"]?default('-')} = y NS ${r["./D:t4"]?default('-')} = x NS <#assign bool = doc["true()"]> ${bool?string} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-new-defaultresolver.txt0000644000175000017500000000026711723544471031716 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} <#attempt> ${"freemarker.template.utility.ObjectConstructor"?new()("java.lang.String", "works")} <#recover> fails libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-local_en.html0000644000175000017500000000026411723544471027617 0ustar ebourgebourg FreeMarker: Localization Test

A simple test follows:

${message}

Hello, in the English language.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-logging.html0000644000175000017500000000044711723544471027474 0ustar ebourgebourg FreeMarker: Logging Test A simple test follows: ${message.test[ "me" ]}

Message exists! ...and even generates output!

Try this for size. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-local.html0000644000175000017500000000026411723544470027134 0ustar ebourgebourg FreeMarker: Localization Test

A simple test follows:

${message}

Hello, in the default language.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-root.html0000644000175000017500000000104511723544470027023 0ustar ebourgebourg<#ftl strict_syntax=false> FreeMarker: Root Lookup Test

A simple test follows:

${message}

Access the same variable via the root variable (dot syntax):

${.data_model.message}

Access the same variable via the root variable (bracket syntax):

${.data_model["message"]}

Ensure that root lookups are unaffected by local variables:

${.data_model.message} ${message} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/undefined.ftl0000644000175000017500000000002511723544471026643 0ustar ebourgebourg${undefined_variable}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-comparisons.html0000644000175000017500000000262211723544470030377 0ustar ebourgebourg FreeMarker: Numeric Operations Test

A simple test follows:

${message}

Start with the increment operator:

<#assign a1 = 0>

a1 = ${a1}

<#assign a1 = a1 + 1>

a1 = ${a1}

<#assign a1 = a1 + 1>

a1 = ${a1}

Now the decrement operator:

<#assign a2 = 5>

a2 = ${a2}

<#assign a2 = a2 - 1>

a2 = ${a2}

<#assign a2 = a2 - 1>

a2 = ${a2}

<#assign a2 = a2 - 1>

a2 = ${a2}

<#assign a2 = a2 - 1>

a2 = ${a2}

<#assign a2 = a2 - 1>

a2 = ${a2}

<#assign a2 = a2 - 1>

a2 = ${a2}

<#assign a2 = a2 - 1>

Now the add operator:

<#assign op1 = 5> <#assign op2 = 3> <#assign op3 = op1 + op2>

op1 = ${op1}, op2 = ${op2}, op3 = ${op3}

<#assign op3 = op3 + op2>

op3 = ${op3}

And the subtract operator:

<#assign op3 = op1 - op2 >

op1 = ${op1}, op2 = ${op2}, op3 = ${op3}

<#assign op3 = op3 - op2 >

op3 = ${op3}

The comparison operators:

<#assign list1 = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]> <#foreach item in list1>

Item is: ${item}

<#if item lt 5>

Item is less than five.

<#if item <= 7>

Item is less than or equals to seven.

<#if item gt 2>

Item is greater than two.

<#if (item >= 10)>

Item is greater than or equal to ten.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-boolean.html0000644000175000017500000000405111723544471027460 0ustar ebourgebourg FreeMarker: Boolean Values Test

A simple test follows:

${message}

<#assign b=true>

Now perform scalar boolean tests:

<#if b> b is true.
<#else> b is false.

<#if false> This can't be!
<#else> This makes sense.

<#if boolean3> boolean3 succeeded.
<#else> boolean3 failed.

<#if boolean4> boolean4 succeeded.
<#else> boolean4 failed.

<#if boolean4 || boolean5> boolean4 || boolean5 succeeded.
<#else> boolean4 || boolean5 failed.

<#if boolean5 || boolean4 || boolean5> boolean5 || boolean4 || boolean5 succeeded.
<#else> boolean5 || boolean4 || boolean5 failed.

<#if boolean4 && boolean5> boolean4 && boolean5 succeeded.
<#else> boolean4 && boolean5 failed.

Now test list models:

<#if list1?exists> list1 succeeded.
<#else> list1 failed.

<#if list2?exists> list2 succeeded.
<#else> list2 failed.

Test hash models:

<#if hash1?exists> hash1 succeeded: ${hash1.temp}
<#else> hash1 failed: ${hash1.temp}

<#if hash2?exists> hash2 succeeded.
<#else> hash2 failed.

Test not operator:

<#if ! boolean1> Not boolean1 succeeded <#else> Not boolean1 failed

<#if !boolean1> Not boolean1 succeeded <#else> Not boolean1 failed

<#if ! boolean2> Not boolean2 succeeded <#else> Not boolean2 failed

<#if !boolean2> Not boolean2 succeeded <#else> Not boolean2 failed

<#if message == "Hello, world!"> Message is "Hello, world!" <#else> Message is something else (${message})

<#if message != "Hello, world!"> Message is not "Hello, world!" -- it's ${message} <#else> Message is "Hello, world!"

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-macro.html0000644000175000017500000000037611723544470027147 0ustar ebourgebourg<#macro m1 a b=a> ${a} ${b} <@m1 a="1"/> <#macro m2 a=b b=""> ${a} ${b} <@m2 b="2"/> <#macro m3 d b=c[a] a=d c={"3":"4"}> ${b} <@m3 d="3"/> <#attempt> <@m3 d="4"/> <#recover> m3 with d="4" Failed! libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-exception3.html0000644000175000017500000000023411723544470030120 0ustar ebourgebourg FreeMarker: Exception Test

A simple test follows:

${message}
${%@#$test}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-charsetinheader_inc2.html0000644000175000017500000000000511723544471032100 0ustar ebourgebourgõÕûÛ libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-include2.html0000644000175000017500000000051511723544472027550 0ustar ebourgebourg FreeMarker: Include Instruction Test

A simple test follows:

${message}

Message exists!

Test normal includes:

Test unparsed includes:

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-numberliteral.html0000644000175000017500000000375211723544471030715 0ustar ebourgebourg FreeMarker: Number Literal Test <#assign hash = {"1" : "one", "12" : "twelve", "2one" : "two-one", "one2" : "one-two"} list = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"], foo = "bar", one = "one", "1" = "one", "12" = "twelve", "2one" = "two-one", "one2" = "one-two", call = "freemarker.testcase.models.SimpleTestMethod"?new() >

A simple test follows:

${message}

Now perform a number assignment:

#{1.300000?double} <#assign mynumber = 1.8, USA="en_US" /> <#assign myfloat = mynumber?float /> My number is: ${mynumber} <#setting locale="en_US"> My float is: #{myfloat ; m6} The int part is: ${myfloat?int} <#assign mymessage = mynumber?string> ${mymessage + 3}

Now use numbers in assignment

<#assign mymessage = 1 + 5> ${mymessage} <#assign mymessage = mymessage + 2> #{mymessage}

Try numbers in tests

<#if (mymessage == 152)> MyMessage is 152 <#else> MyMessage is not 152, its: ${mymessage}. 5)> MyMessage is greater than five. <#case 1> MyMessage is one <#break> <#case 15> MyMessage is fifteen <#break> <#case 152> MyMessage is one-five-two <#break> <#default> MyMessage is: ${mymessage}. <#break>

Now for numbers in dynamic keys:

<#assign one = 1> <#assign two = 2> ${list[ 1 ]} ${list[ 1 + 2 ]}

Numbers in hashes:

${hash[ 1 + "2" ]} ${hash[ "1" + 2 ]} ${hash[ "1" + two ]}

Numbers in method calls:

${call( 1 )} ${call( one )} ${call( one + "2" )} ${call( one + 2 )} ${call( 1 + 2 )} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-exthash.html0000644000175000017500000000123611723544471027507 0ustar ebourgebourg FreeMarker: Extended Hash Test

A simple test follows:

${message}

A hash set of ${animals?size} animals follows:

${animal}, .

The first animal is an ${animalKeys?first}, and the last is a ${animalKeys?last}.

A hash set of ${animals?size} digits follows:

${number}, .

The zebra number is ${animals.zebra}.

The end.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-outputencoding1.txt0000644000175000017500000000044611723544470031047 0ustar ebourgebourgOutput charset: ${.output_encoding?default("undefined")} URL escaping charset: ${.url_escaping_charset?default("undefined")} <#assign s="a/%b"> <#setting url_escaping_charset="UTF-16"> ${s?url} ${s?url} <#setting url_escaping_charset="ISO-8859-1"> ${s?url} ${s?url} ${s?url('UTF-16')} ${s?url}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-extlist.html0000644000175000017500000000114511723544470027535 0ustar ebourgebourg FreeMarker: Extended List Test <#assign animals = ["aardvark", "kiwi", "gecko", "cat", "dog", "elephant", "squirrel", "zebra"]>

A simple test follows:

${message}

A list of ${animals?size} animals follows:

<#foreach animal in animals> ${animal}<#if animal_has_next>, <#else>.

The first animal is an ${animals?first}, and the last is a ${animals?last}.

The end.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-identifier.html0000644000175000017500000000062411723544471030165 0ustar ebourgebourg FreeMarker: Identifier Test

A simple test follows:

${message}

A tag inside a tag...

<#assign f="f"> >this is a test>no message
Blah <b>This is a teststrong>no message> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-iso8601.txt0000644000175000017500000001165211723544472027033 0ustar ebourgebourg<#assign d = "2010-05-15 22:38:05:23 +0200"?datetime("yyyy-MM-dd HH:mm:ss:S Z")> <#setting time_zone="GMT+02"> ${d?iso_utc} = 2010-05-15T20:38:05Z ${d?iso_utc_ms} = 2010-05-15T20:38:05.023Z ${d?iso_utc_m} = 2010-05-15T20:38Z ${d?iso_utc_h} = 2010-05-15T20Z ${d?iso_utc_nz} = 2010-05-15T20:38:05 ${d?iso_utc_ms_nz} = 2010-05-15T20:38:05.023 ${d?iso_utc_m_nz} = 2010-05-15T20:38 ${d?iso_utc_h_nz} = 2010-05-15T20 ${d?iso_local} = 2010-05-15T22:38:05+02:00 ${d?iso_local_ms} = 2010-05-15T22:38:05.023+02:00 ${d?iso_local_m} = 2010-05-15T22:38+02:00 ${d?iso_local_h} = 2010-05-15T22+02:00 ${d?iso_local_nz} = 2010-05-15T22:38:05 ${d?iso_local_ms_nz} = 2010-05-15T22:38:05.023 ${d?iso_local_m_nz} = 2010-05-15T22:38 ${d?iso_local_h_nz} = 2010-05-15T22 ${d?date?iso_utc} = 2010-05-15 ${d?date?iso_utc_ms} = 2010-05-15 ${d?date?iso_utc_m} = 2010-05-15 ${d?date?iso_utc_h} = 2010-05-15 ${d?date?iso_utc_nz} = 2010-05-15 ${d?date?iso_utc_ms_nz} = 2010-05-15 ${d?date?iso_utc_m_nz} = 2010-05-15 ${d?date?iso_utc_h_nz} = 2010-05-15 ${d?date?iso_local} = 2010-05-15 ${d?date?iso_local_ms} = 2010-05-15 ${d?date?iso_local_m} = 2010-05-15 ${d?date?iso_local_h} = 2010-05-15 ${d?date?iso_local_nz} = 2010-05-15 ${d?date?iso_local_ms_nz} = 2010-05-15 ${d?date?iso_local_m_nz} = 2010-05-15 ${d?date?iso_local_h_nz} = 2010-05-15 ${d?time?iso_utc} = 20:38:05Z ${d?time?iso_utc_ms} = 20:38:05.023Z ${d?time?iso_utc_m} = 20:38Z ${d?time?iso_utc_h} = 20Z ${d?time?iso_utc_nz} = 20:38:05 ${d?time?iso_utc_ms_nz} = 20:38:05.023 ${d?time?iso_utc_m_nz} = 20:38 ${d?time?iso_utc_h_nz} = 20 ${d?time?iso_local} = 22:38:05+02:00 ${d?time?iso_local_ms} = 22:38:05.023+02:00 ${d?time?iso_local_m} = 22:38+02:00 ${d?time?iso_local_h} = 22+02:00 ${d?time?iso_local_nz} = 22:38:05 ${d?time?iso_local_ms_nz} = 22:38:05.023 ${d?time?iso_local_m_nz} = 22:38 ${d?time?iso_local_h_nz} = 22 <#assign dStrange = "600-01-01 23:59:59:123 +0000"?datetime("yyyy-MM-dd HH:mm:ss:S Z")> ${dStrange?iso_utc_ms} = 0600-01-01T23:59:59.123Z <#setting time_zone="GMT+03"> <#-- should not mater --> ${d?iso("UTC")} = 2010-05-15T20:38:05Z ${d?iso_ms("UTC")} = 2010-05-15T20:38:05.023Z ${d?iso_m("UTC")} = 2010-05-15T20:38Z ${d?iso_h("UTC")} = 2010-05-15T20Z ${d?iso_nz("UTC")} = 2010-05-15T20:38:05 ${d?iso_ms_nz("UTC")} = 2010-05-15T20:38:05.023 ${d?iso_m_nz("UTC")} = 2010-05-15T20:38 ${d?iso_h_nz("UTC")} = 2010-05-15T20 ${d?iso("GMT+02")} = 2010-05-15T22:38:05+02:00 ${d?iso_ms("GMT+02")} = 2010-05-15T22:38:05.023+02:00 ${d?iso_m("GMT+02")} = 2010-05-15T22:38+02:00 ${d?iso_h("GMT+02")} = 2010-05-15T22+02:00 ${d?iso_nz("GMT+02")} = 2010-05-15T22:38:05 ${d?iso_ms_nz("GMT+02")} = 2010-05-15T22:38:05.023 ${d?iso_m_nz("GMT+02")} = 2010-05-15T22:38 ${d?iso_h_nz("GMT+02")} = 2010-05-15T22 ${d?date?iso("UTC")} = 2010-05-15 ${d?date?iso_ms("UTC")} = 2010-05-15 ${d?date?iso_m("UTC")} = 2010-05-15 ${d?date?iso_h("UTC")} = 2010-05-15 ${d?date?iso_nz("UTC")} = 2010-05-15 ${d?date?iso_ms_nz("UTC")} = 2010-05-15 ${d?date?iso_m_nz("UTC")} = 2010-05-15 ${d?date?iso_h_nz("UTC")} = 2010-05-15 ${d?date?iso("GMT+02")} = 2010-05-15 ${d?date?iso_ms("GMT+02")} = 2010-05-15 ${d?date?iso_m("GMT+02")} = 2010-05-15 ${d?date?iso_h("GMT+02")} = 2010-05-15 ${d?date?iso_nz("GMT+02")} = 2010-05-15 ${d?date?iso_ms_nz("GMT+02")} = 2010-05-15 ${d?date?iso_m_nz("GMT+02")} = 2010-05-15 ${d?date?iso_h_nz("GMT+02")} = 2010-05-15 ${d?time?iso("UTC")} = 20:38:05Z ${d?time?iso_ms("UTC")} = 20:38:05.023Z ${d?time?iso_m("UTC")} = 20:38Z ${d?time?iso_h("UTC")} = 20Z ${d?time?iso_nz("UTC")} = 20:38:05 ${d?time?iso_ms_nz("UTC")} = 20:38:05.023 ${d?time?iso_m_nz("UTC")} = 20:38 ${d?time?iso_h_nz("UTC")} = 20 ${d?time?iso("GMT+02")} = 22:38:05+02:00 ${d?time?iso_ms("GMT+02")} = 22:38:05.023+02:00 ${d?time?iso_m("GMT+02")} = 22:38+02:00 ${d?time?iso_h("GMT+02")} = 22+02:00 ${d?time?iso_nz("GMT+02")} = 22:38:05 ${d?time?iso_ms_nz("GMT+02")} = 22:38:05.023 ${d?time?iso_m_nz("GMT+02")} = 22:38 ${d?time?iso_h_nz("GMT+02")} = 22 ${d?iso(javaUTC)} = 2010-05-15T20:38:05Z ${d?iso(javaGMT02)} = 2010-05-15T22:38:05+02:00 ${d?iso(adaptedToStringScalar)} = 2010-05-15T22:38:05+02:00 <#assign d = "12:00:00:1 +0000"?time("HH:mm:ss:S Z")> ${d?iso_utc_ms} = 12:00:00.001Z <#assign d = "12:00:00:10 +0000"?time("HH:mm:ss:S Z")> ${d?iso_utc_ms} = 12:00:00.01Z <#assign d = "12:00:00:100 +0000"?time("HH:mm:ss:S Z")> ${d?iso_utc_ms} = 12:00:00.1Z <#assign d = "12:00:00:0 +0000"?time("HH:mm:ss:S Z")> ${d?iso_utc_ms} = 12:00:00Z <#setting time_zone="GMT+02"> <#assign d = "2010-05-15"?date("yyyy-MM-dd")> ${d?iso_local} = 2010-05-15 ${d?iso_utc} = 2010-05-14 <#setting time_zone="GMT+02:30"> <#assign d = "2010-05-15"?datetime("yyyy-MM-dd")> ${d?iso_local} = 2010-05-15T00:00:00+02:30 <#setting time_zone="America/New_York"> ${"2010-05-09 20:00 +0000"?datetime("yyyy-MM-dd HH:mm Z")?iso_local} = 2010-05-09T16:00:00-04:00 ${"2010-01-01 20:00 +0000"?datetime("yyyy-MM-dd HH:mm Z")?iso_local} = 2010-01-01T15:00:00-05:00 <#attempt> ${d?iso("no such zone")} <#recover> unrecognized time zone name libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-models.html0000644000175000017500000000304511723544470027325 0ustar ebourgebourg FreeMarker: Test of Multiple Model implementations

Let's begin with a simple model:

${message}

Cool, now get into the first model. This implements a scalar, list, and hash as a single class. Let's try some tests...

${data}

Now as a list...

<#foreach item in data>${item}

Index into a list...

${data[ 1 ]}

List size is: ${data.size}

List size is: ${data["size"]}

Now, again, as a hash. First using dot notation, then using [] notation:

${data.selftest}

${data["selftest"]}

Now for the tricky stuff... use a model to index into another model...

${test}

${data[ test ]}

${self}

${data[ self + "test" ]}

Same thing, this time a List index...

${zero}

${data[ zero ]}

${data[ zero + 1 ]}

Now, do the same recursively...

${data}

${data.model2}

${data.model2( "test" )}

${data.model2( data, data.selftest, message )}

Does this really not work?

${data[ 10 ]}

${data[ 10 ].selftest}

${data[ 10 ].message}

(Again, with Hashes)

${data.nesting1.nested}

${data.nesting1.nested.selftest}

${data["nesting1"].nested}

${data["nesting1"].nested["selftest"]}

${data["nesting1"]["nested"]["selftest"]}

As I suspected! (Manual on Expressions needs updating.)

Second test on list size

${data.one.size}

${data.one["size"]}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-wsstripinheader_inc.txt0000644000175000017500000000006111723544471031755 0ustar ebourgebourg<#ftl strip_whitespace="yes"> a <#assign x = 1> blibfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-hashliteral.html0000644000175000017500000000267711723544470030354 0ustar ebourgebourg FreeMarker: Hash Literal Test

A simple test follows:

${message}

Now perform a hash assignment:

<#assign mymessage = "hello", foo="bar", one="1"> <#assign test = { "test1": "test23", "test45" : message, mymessage : "hello all", foo: one}> ${test.test1} ${test.test45} ${test.hello} ${test.bar}

Now update the assignment and repeat:

<#assign mymessage = "world"> ${test.test1} ${test.test45} ${test.hello} ${test.bar}

Now reassign the list and repeat:

<#assign hash= {"temp" : "Temporary"}> <#assign test = { "test1" : "test23", "test45" : message, mymessage : "hello all", foo : one, "hash" : hash[ "temp" ], "true" : hash.temp, "newhash" : hash}> ${test.test1} ${test.test45} ${test.hello?if_exists} ${test.bar} ${test.hash} ${test.true} ${test.newhash.temp}

Pathological case: zero item hash:

<#assign test = {}> ${test.test1?if_exists}

Hash of number literals:

<#assign test = {"1" : 2}> ${test["1"]}

Hash concatenation:

<#assign cc = { "a" : 1, "b" : 2 } + { "b" : 3, "c" : 4 }> <#list cc?keys?sort as key> ${key} => ${cc[key]}

Empty hash concatenation:

${({} + { "a" : "foo" }).a}, ${({ "a" : "bar" } + {}).a} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/0000755000175000017500000000000012164627123025462 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/test-new-optin-2.txt0000644000175000017500000000023411723544470031261 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} <#attempt> ${"freemarker.testcase.models.NewTestModel2"?new("works")} <#recover> fails libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/test-include-subdir2.html0000644000175000017500000000005111723544470032317 0ustar ebourgebourg

This is test-include-subdir2.html

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/test-new-optin.txt0000644000175000017500000000027711723544471031132 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} <#attempt> ${"freemarker.testcase.models.NewTestModel2"?new("works")} <#recover> fails <#include "test-new-optin-2.txt">libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/test-include-subdir.html0000644000175000017500000000056411723544470032246 0ustar ebourgebourg

This is test-include-subdir.html

Testing including from same directory

<#include "test-include-subdir2.html">

Testing including from relative parent

<#include "../test-included.html">

Testing including from loader root

<#include "/test-included.html">

Testing including through acquisition

<#include "*/subdir/test-include-subdir2.html">libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/subsub/0000755000175000017500000000000012164627123026765 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/subdir/subsub/test-new-optin.txt0000644000175000017500000000023411723544470032425 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} <#attempt> ${"freemarker.testcase.models.NewTestModel2"?new("works")} <#recover> fails libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-sequencebuiltins.txt0000644000175000017500000001704311723544467031310 0ustar ebourgebourg<#setting locale="en_US"> <#setting number_format="0.#########"> <#assign ls = []?sort> <#list ls as i> - ${i} Size ${ls?size} Sorting scalars: ---------------- String order: <#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort> <#list ls as i> - ${i} First: ${ls?first} Last: ${ls?last} Size ${ls?size} Numerical order: <#assign ls = [123?byte, 543, -324, -34?float, 0.11, 0, 111?int, 0.1?double, 1, 5]?sort> <#list ls as i> - ${i} First: ${ls?first} Last: ${ls?last} Size ${ls?size} Date/time order: <#assign x = [ '08:05'?time('HH:mm'), '18:00'?time('HH:mm'), '06:05'?time('HH:mm'), '08:15'?time('HH:mm')]> <#list x?sort as i> - ${i?string('HH:mm')} Boolean order: <#assign x = [ true, false, false, true]> <#list x?sort as i> - ${i?string} Sorting hashes: --------------- <#assign ls = [ {"name":"whale", "weight":2000?short}, {"name":"Barbara", "weight":53}, {"name":"zeppelin", "weight":-200?float}, {"name":"aardvark", "weight":30?long}, {"name":"beetroot", "weight":0.3} ]> Order by name: <#assign ls = ls?sort_by("name")> <#list ls as i> - ${i.name}: ${i.weight} Order by weight: <#assign ls = ls?sort_by("weight")> <#list ls as i> - ${i.name}: ${i.weight} Order by a.x.v: <#assign x = [ {"a": {"x": {"v": "qweqw", "w": "asd"}, "y": '1998-02-20'?date('yyyy-MM-dd')}}, {"a": {"x": {"v": "aqweqw", "w": "asd"}, "y": '1999-01-20'?date('yyyy-MM-dd')}}, {"a": {"x": {"v": "dfgdf", "w": "asd"}, "y": '1999-04-20'?date('yyyy-MM-dd')}}, {"a": {"x": {"v": "utyu", "w": "asd"}, "y": '1999-04-19'?date('yyyy-MM-dd')}}]> <#list x?sort_by(['a', 'x', 'v']) as i> - ${i.a.x.v} Order by a.y, which is a date: <#list x?sort_by(['a', 'y']) as i> - ${i.a.y?string('yyyy-MM-dd')} Reverse: -------- Order by weight desc: <#assign ls = ls?reverse> <#list ls as i> - ${i.name}: ${i.weight} Order by weight desc desc: <#assign ls = ls?reverse> <#list ls as i> - ${i.name}: ${i.weight} Order by weight desc desc desc: <#assign ls = ls?reverse> <#list ls as i> - ${i.name}: ${i.weight} Contains: --------- <#macro test> <#assign x = [1, "2", true, [1,2,3], {"a":1}, test, '1992-02-21'?date('yyyy-MM-dd')]> True: ${x?seq_contains(1.0)?string} ${x?seq_contains("2")?string} ${x?seq_contains(true)?string} ${x?seq_contains('1992-02-21'?date('yyyy-MM-dd'))?string} ${abcSet?seq_contains("a")?string} ${abcSet?seq_contains("b")?string} ${abcSet?seq_contains("c")?string} False: ${x?seq_contains("1")?string} ${x?seq_contains(2)?string} ${x?seq_contains(false)?string} ${x?seq_contains('1992-02-22'?date('yyyy-MM-dd'))?string} ${abcSet?seq_contains("A")?string} ${abcSet?seq_contains(1)?string} ${abcSet?seq_contains(true)?string} <#assign x = []> False: ${x?seq_contains(1)?string} Index_of: --------- <#assign x = [1, "2", true, [1,2,3], {"a":1}, test, '1992-02-21'?date('yyyy-MM-dd')]> 0 = ${x?seq_index_of(1.0)} 1 = ${x?seq_index_of("2")} 2 = ${x?seq_index_of(true)} 6 = ${x?seq_index_of('1992-02-21'?date('yyyy-MM-dd'))} 0 = ${abcSet?seq_index_of("a")} 1 = ${abcSet?seq_index_of("b")} 2 = ${abcSet?seq_index_of("c")} -1 = ${x?seq_index_of("1")} -1 = ${x?seq_index_of(2)} -1 = ${x?seq_index_of(false)} -1 = ${x?seq_index_of('1992-02-22'?date('yyyy-MM-dd'))} -1 = ${abcSet?seq_index_of("A")} -1 = ${abcSet?seq_index_of(1)} -1 = ${abcSet?seq_index_of(true)} <#assign x = []> -1 = ${x?seq_index_of(1)} Last_index_of: -------------- <#assign x = [1, "2", true, [1,2,3], {"a":1}, test, 1, '1992-02-21'?date('yyyy-MM-dd')]> 6 = ${x?seq_last_index_of(1.0)} 1 = ${x?seq_last_index_of("2")} 2 = ${x?seq_last_index_of(true)} 7 = ${x?seq_last_index_of('1992-02-21'?date('yyyy-MM-dd'))} -1 = ${x?seq_last_index_of("1")} 0 = ${abcSet?seq_last_index_of("a")} 1 = ${abcSet?seq_last_index_of("b")} 2 = ${abcSet?seq_last_index_of("c")} -1 = ${abcSet?seq_last_index_of("A")} Index_of and last_index_of with starting indices ------------------------------------------------ <#assign names = ["Joe", "Fred", "Joe", "Susan"]> seq_index_of "Joe": 0 = ${names?seq_index_of("Joe", -2)} 0 = ${names?seq_index_of("Joe", -1)} 0 = ${names?seq_index_of("Joe", 0)} 2 = ${names?seq_index_of("Joe", 1)} 2 = ${names?seq_index_of("Joe", 2)} -1 = ${names?seq_index_of("Joe", 3)} -1 = ${names?seq_index_of("Joe", 4)} seq_last_index_of "Joe": -1 = ${names?seq_last_index_of("Joe", -2)} -1 = ${names?seq_last_index_of("Joe", -1)} 0 = ${names?seq_last_index_of("Joe", 0)} 0 = ${names?seq_last_index_of("Joe", 1)} 2 = ${names?seq_last_index_of("Joe", 2)} 2 = ${names?seq_last_index_of("Joe", 3)} 2 = ${names?seq_last_index_of("Joe", 4)} seq_index_of "Susan": 3 = ${names?seq_index_of("Susan", -2)} 3 = ${names?seq_index_of("Susan", -1)} 3 = ${names?seq_index_of("Susan", 0)} 3 = ${names?seq_index_of("Susan", 1)} 3 = ${names?seq_index_of("Susan", 2)} 3 = ${names?seq_index_of("Susan", 3)} -1 = ${names?seq_index_of("Susan", 4)} seq_last_index_of "Susan": -1 = ${names?seq_last_index_of("Susan", -2)} -1 = ${names?seq_last_index_of("Susan", -1)} -1 = ${names?seq_last_index_of("Susan", 0)} -1 = ${names?seq_last_index_of("Susan", 1)} -1 = ${names?seq_last_index_of("Susan", 2)} 3 = ${names?seq_last_index_of("Susan", 3)} 3 = ${names?seq_last_index_of("Susan", 4)} seq_index_of "a": 0 = ${abcSet?seq_index_of("a", -2)} 0 = ${abcSet?seq_index_of("a", -1)} 0 = ${abcSet?seq_index_of("a", 0)} -1 = ${abcSet?seq_index_of("a", 1)} -1 = ${abcSet?seq_index_of("a", 2)} -1 = ${abcSet?seq_index_of("a", 3)} -1 = ${abcSet?seq_index_of("a", 4)} seq_index_of "b": 1 = ${abcSet?seq_index_of("b", -2)} 1 = ${abcSet?seq_index_of("b", -1)} 1 = ${abcSet?seq_index_of("b", 0)} 1 = ${abcSet?seq_index_of("b", 1)} -1 = ${abcSet?seq_index_of("b", 2)} -1 = ${abcSet?seq_index_of("b", 3)} seq_index_of "c": 2 = ${abcSet?seq_index_of("c", -2)} 2 = ${abcSet?seq_index_of("c", -1)} 2 = ${abcSet?seq_index_of("c", 0)} 2 = ${abcSet?seq_index_of("c", 1)} 2 = ${abcSet?seq_index_of("c", 2)} -1 = ${abcSet?seq_index_of("c", 3)} seq_last_index_of "a": -1 = ${abcSet?seq_last_index_of("a", -2)} -1 = ${abcSet?seq_last_index_of("a", -1)} 0 = ${abcSet?seq_last_index_of("a", 0)} 0 = ${abcSet?seq_last_index_of("a", 1)} 0 = ${abcSet?seq_last_index_of("a", 2)} 0 = ${abcSet?seq_last_index_of("a", 3)} 0 = ${abcSet?seq_last_index_of("a", 4)} seq_last_index_of "b": -1 = ${abcSet?seq_last_index_of("b", -2)} -1 = ${abcSet?seq_last_index_of("b", -1)} -1 = ${abcSet?seq_last_index_of("b", 0)} 1 = ${abcSet?seq_last_index_of("b", 1)} 1 = ${abcSet?seq_last_index_of("b", 2)} 1 = ${abcSet?seq_last_index_of("b", 3)} seq_last_index_of "c": -1 = ${abcSet?seq_last_index_of("c", -2)} -1 = ${abcSet?seq_last_index_of("c", -1)} -1 = ${abcSet?seq_last_index_of("c", 0)} -1 = ${abcSet?seq_last_index_of("c", 1)} 2 = ${abcSet?seq_last_index_of("c", 2)} 2 = ${abcSet?seq_last_index_of("c", 3)} Chunk ----- <#assign ls = ['a', 'b', 'c', 'd', 'e', 'f', 'g']> <#list ['NULL', '-'] as fill> <#list [1, 2, 3, 4, 5, 10] as columns> <@printTable ls, columns, fill /> <@printTable [1, 2, 3, 4, 5, 6, 7, 8, 9], 3, 'NULL' /> <@printTable [1, 2, 3, 4, 5, 6, 7, 8, 9], 3, '-' /> <@printTable [1], 3, 'NULL' /> <@printTable [1], 3, '-' /> <@printTable [], 3, 'NULL' /> <@printTable [], 3, '-' /> <#macro printTable ls columns fill> columns = ${columns}, fill = ${fill}:<#lt> <#if fill='NULL'> <#local rows = ls?chunk(columns)> <#else> <#local rows = ls?chunk(columns, fill)> Rows: ${rows?size} <#list rows as row> <#list row as i>${i} <-- Columns: ${row?size} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-loopvar.txt0000644000175000017500000000105311723544471027375 0ustar ebourgebourg<#setting locale="en_US"> --- <#macro myLoop from to> <#list from..to as x> - <#nested x>* <#list 2..1 as i> ${i} <@myLoop from=1 to=3; i> L1 ${i} <@myLoop from=1 to=2; i> L2 ${i}: <#list 1..3 as i>${i}; --- <#macro repeat count> <#list 1..count as x> <#nested x, x/2, x==count> <#macro test2> <#local c = 123> <@repeat count=4 ; c, halfc, last> <#local c = .locals.c + 0.1> ${c} ${halfc}<#if last> Last! ${c} <@test2/> ---libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-new-optin.txt0000644000175000017500000000043511723544470027635 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} <#attempt> ${"freemarker.testcase.models.NewTestModel2"?new("works")} <#recover> fails <#include "subdir/test-new-optin.txt"> <#include "subdir/test-new-optin-2.txt"> <#include "subdir/subsub/test-new-optin.txt">libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-dateformat.html0000644000175000017500000000171311723544471030171 0ustar ebourgebourg<#setting locale="en_US"> <#setting time_zone="GMT"> <#setting datetime_format=""> ${date} ${unknownDate?datetime} ${date?string} ${date?string[""]} ${date?string["short"]} ${date?string["medium"]} ${date?string["long"]} ${date?string["short_short"]} ${date?string["short_medium"]} ${date?string["short_long"]} ${date?string["medium_short"]} ${date?string["medium_medium"]} ${date?string["medium_long"]} ${date?string["long_short"]} ${date?string["long_medium"]} ${date?string["long_long"]} ${unknownDate?date} ${date?date?string[""]} ${date?date?string["short"]} ${date?date?string["medium"]} ${date?date?string["long"]} ${unknownDate?time} ${date?time?string[""]} ${date?time?string["short"]} ${date?time?string["medium"]} ${date?time?string["long"]} <#setting locale="hu_hu"> <#setting datetime_format="long_long"> ${date} <#setting locale="en_US"> <#setting datetime_format="EEE, dd MMM yyyyy HH:mm:ss z"> ${date} ${unknownDate?string["EEE, dd MMM yyyyy HH:mm:ss z"]}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-compress.html0000644000175000017500000000141211723544471027672 0ustar ebourgebourg FreeMarker: Compress Test <#assign utility= {utility : "freemarker.template.utility.StandardCompress"?new()>

A simple test follows:

${message}

<#compress>

This is the same message, using the "compress" tag:

${message}

<@utility.standardCompress buffer_size=8>

This is the same message, using the "StandardCompress" transform model:

${message}

<@utility.standardCompress single_line=true>

This multi-line message should be compressed to a single line.

An example where the first character is not whitespace but the second character is:

<#compress>x y

The end.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-outputencoding3.txt0000644000175000017500000000045411723544467031056 0ustar ebourgebourgOutput charset: ${.output_encoding?default("undefined")} URL escaping charset: ${.url_escaping_charset?default("undefined")} <#assign s="a/%b"> UTF-16: ${s?url} ISO-8859-1: ${s?url('ISO-8859-1')} UTF-16: ${s?url} <#setting url_escaping_charset="ISO-8859-1"> ISO-8859-1: ${s?url} ISO-8859-1: ${s?url}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-comment.html0000644000175000017500000000074211723544470027505 0ustar ebourgebourg<#ftl strict_syntax=false> FreeMarker: Comment Test <#-- A simple test follows: ${message} A more rigorous test, showing that we're not faking it: ${message@#$%&} --><#-- > --><#-- -> --><#-- -- --><#-- -- > --> >

Message exists! ...and even generates output!

a <#-- < --> b a <#--
- -- --> b libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-outputencoding2.txt0000644000175000017500000000045411723544471031050 0ustar ebourgebourgOutput charset: ${.output_encoding?default("undefined")} URL escaping charset: ${.url_escaping_charset?default("undefined")} <#assign s="a/%b"> UTF-16: ${s?url} ISO-8859-1: ${s?url('ISO-8859-1')} UTF-16: ${s?url} <#setting url_escaping_charset="ISO-8859-1"> ISO-8859-1: ${s?url} ISO-8859-1: ${s?url}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-nested1.txt0000644000175000017500000000075211723544471027263 0ustar ebourgebourg<#macro repeat count> <#local y = "test"> <#foreach x in 1..count> ${y} ${count}/${x}: <#nested x, "asdf"> <#-- the second body parameter is not used below --> <@repeat count=3>${y?default("undefined")} ${x?default("undefined")} ${count?default("undefined")} <#global x = "X"> <#global y = "Y"> <#global count = "Count"> <@repeat count=3 ; param1>${y?default("undefined")} ${x?default("undefined")} ${count?default("undefined")} ${param1}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-strictinheader.html0000644000175000017500000000021111723544471031043 0ustar ebourgebourg<#ftl strict_syntax="yes"> 1 <#include "test-strictinheader_inc1.html"> <#include "test-strictinheader_inc2.html"> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-import_lib.txt0000644000175000017500000000034311723544470030053 0ustar ebourgebourg<#macro test foo> Test ${foo}. Email: ${mail} <#if .main.mail?exists> Email in the root: ${.main.mail} <#function doubleUp foo> <#return foo+foo> <#assign mail = "jsmith@acme.com">libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-precedence.html0000644000175000017500000000107311723544471030137 0ustar ebourgebourg FreeMarker: Operator Precedence Test <#assign patate1 = "test"> <#assign patate2 = "test"> <#assign patate3 = "test"> <#if patate1 == patate2 && patate2 == patate3> @@@@@@@@@@@

<#if patate1?exists && patate2 == patate3> ##########

<#if patate2 == patate2 && (patate2==patate2)> &&&&&&&&&&&

<#if (patate2 == patate2) && (patate2==patate2)> !!!!!!!!!!!

<#if (patate2 == patate2) && patate2==patate2> $$$$$$$$$$$ libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-function.html0000644000175000017500000000320011723544471027661 0ustar ebourgebourg<#ftl strict_syntax="false"> FreeMarker: Function Test

A simple test follows:

${message}

Now perform function tests:

<#assign urls = {"home" : "/home.html", "about" : "/about.html"}> <#assign images = {"home" : "/images/home.png", "about" : "/image/about-us.jpeg"}> <#assign preferences = {"showImages" : true}> <#macro français(url, image, alt)>
${alt} ${alt} ${var} was here.

Function is defined, now let's call it:

<#t>

Again, but with different parameters:

<@français url=urls.about image=images.about alt="About Us" /> <#if var?exists> Something is wrong here. Good.

A recursive function call:

0)> ${a} <@recurse urls />

Test "catch-all" macro parameter:

<#macro "catch-all" foo bar...> foo=${foo} baz=[<#list bar?keys as key>${key}=${bar[key]}<#if key_has_next>, ] <#assign catchall = .namespace["catch-all"]> <@catchall foo="a"/> <@catchall foo="a" bar="b"/> <@catchall foo="a" bar="b" baz="c"/> <#macro fmt pattern args...> <#list args as arg> <#local pattern = pattern?replace("{" + arg_index + "}", arg)> ${pattern}<#lt> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-listiterators.html0000644000175000017500000000153711723544470030756 0ustar ebourgebourg FreeMarker: List Iterator Test <#assign list= ["one", "two", "three", "four", "five"]> <#assign hash = {"key", list}> <#assign hash2 = {"value", hash}>

A simple test follows:

${message}

Now iterate over a list:

<#foreach item in list>

${item}

Now iterate again:

<#list list as item>

${item_index}. ${item}

Iterate over a list in a hash:

<#list hash.key as item>

${item}

<#foreach item in hash.key>

${item}

<#foreach item in hash[ "key" ]>

${item}

<#list hash["key"] as item>

${item}

Now test the list and foreach keywords...

<#list hash2["value"].key as key>

${key}

<#foreach az in hash2.value.key>

${az}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-beans.html0000644000175000017500000000175011723544471027134 0ustar ebourgebourg<#list array as item> ${item} ${array?size} ${array[0]} ${array[1]} <#list list as item> ${item} ${list.size()} <#if list.isEmpty()>empty<#else>not empty ${list[0]} ${map.key} ${map(objKey)} ${obj.foo} <#if obj.foo?exists>hasfoo<#else>nofoo <#if obj.baz?exists>hasbaz<#else>nobaz ${obj.bar[0]} ${obj.bar(0)} ${obj.getFoo()} ${obj.overloaded(1?int)} ${obj.overloaded("String")} ${resourceBundle.message} ${resourceBundle("format", date)} <#assign static = statics["freemarker.testcase.models.BeanTestClass"]> ${static.staticMethod()} ${static.staticOverloaded[1]} ${static.staticOverloaded("String")} ${static.STATIC_FINAL_FIELD} ${static.STATIC_FIELD} <#assign enum = enums["freemarker.testcase.models.EnumTestClass"]> ${enum.ONE} ${enum.TWO} ${enum.THREE} ${(enum.ONE == enum.ONE)?string("true", "false")} ${(enum.ONE == enum.TWO)?string("true", "false")} ${enums["freemarker.testcase.models.BeanTestClass"]?exists?string("true", "false")} ${obj.something}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-interpret.html0000644000175000017500000000040611723544470030054 0ustar ebourgebourg<#global x=["a", "b", "c"]> <#global templateSource = r"<#foreach y in x>${y}"> <#transform templateSource?interpret>def <#transform [templateSource]?interpret>def <#transform [templateSource,"id"]?interpret>def libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-xmlns.html0000644000175000017500000000104111723544470027175 0ustar ebourgebourg<#ftl ns_prefixes = {"D" : "http://example.com/eBook"}> ${doc.@@markup} <#recurse doc > <#macro book> <#recurse .node.title>

<#recurse .node.title>

<#recurse> <#macro chapter>

<#recurse .node.title>

<#recurse> <#macro para>

<#recurse> <#macro title> <#-- We have handled this element imperatively, so we do nothing here. --> <#macro @text>${.node?html}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-default.ftl0000644000175000017500000000033311723544471027305 0ustar ebourgebourg${UNDEFINED!"foo"} <#assign duck = (FOO.BAR)!"luck"> ${duck} <#list UNDEFINED![] as item> ${item} ${UNDEFINED![]?size} <#if UNDEFINED??> UNDEFINED is defined. <#else> UNDEFINED is undefined. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-specialvars.txt0000644000175000017500000000106411723544471030231 0ustar ebourgebourg<#-- Mostly just checks if the expressions doesn't fail --> <#assign works = .data_model> <#attempt> ${noSuchVariableExists} <#recover> <#assign works = .error> <#assign works = .globals> ${.lang} == en ${.locale} == en_US <#assign works = .locals!> <#assign works = .main> <#assign works = .node!> ${.output_encoding?lower_case} == utf-8 ${.template_name} == test-specialvars.txt ${.url_escaping_charset?lower_case} == iso-8859-1 <#assign foo = "x"> ${.vars['foo']} == x <#assign works = .version> ${.now?is_date?string} == truelibfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/string-builtins-regexps.txt0000644000175000017500000000704011723544471031550 0ustar ebourgebourg${"test"?matches('test')?string} == true ${"test"?matches('test', '')?string} == true ${"TEST"?matches('test')?string} == false ${"TEST"?matches('test', 'i')?string} == true ${"test\nfoo"?matches('.*^foo')?string} == false ${"test\nfoo"?matches(r'.*\n^foo', 'm')?string} == true ${"test\nfoo"?matches('test.foo')?string} == false ${"test\nfoo"?matches('test.foo', 's')?string} == true ${"test\nFoo"?matches('.*foo', 's')?string} == false ${"test\nFoo"?matches('.*foo', 'i')?string} == false ${"test\nFoo"?matches('.*foo', 'im')?string} == false ${"test\nFoo"?matches('.*foo', 'si')?string} == true ${"test\nFoo"?matches('.*foo', 'is')?string} == true ${"test\nFoo"?matches('.*foo', 'mis')?string} == true ${"test\nFoo"?matches('.*\n^foo', 'm')?string} == false ${"test\nFoo"?matches('.*\n^foo', 'i')?string} == false ${"test\nFoo"?matches('.*\n^foo', 'im')?string} == true ${"test\nFoo"?matches('.*\n^foo', 'mi')?string} == true ${"test\nFoo"?matches('.*^foo', 'ism')?string} == true ${"test\nFoo"?matches('.*^foo', 'smi')?string} == true <#assign s = "Code without test coverage\nis considered to be BROKEN"> Lower 'c'-words: <#list s?matches('c[a-z]*') as m> - ${m} Any 'c'-words: <#list s?matches('c[a-z]*', 'i') as m> - ${m} Lower line-last words: <#list s?matches('[a-z]+$', 'm') as m> - ${m} Any line-last words: <#list s?matches('[a-z]+$', 'mi') as m> - ${m} Any last words: <#list s?matches('[a-z]+$', 'i') as m> - ${m} c-word with follower: <#list s?matches('(c[a-z]*+).([a-z]++)', 'is') as m> - "${m?j_string}" Groups: <#list m?groups as g>"${g?j_string}"<#if g_has_next>, c-word with follower in the same line: <#list s?matches('c[a-z]*+.[a-z]++', 'i') as m> - ${m} Lower c-word with follower in the same line: <#list s?matches('c[a-z]*+.[a-z]++', '') as m> - ${m} <#attempt> Ignored but logged in 2.3: ${s?matches('broken', 'I')?string} == false <#recover> Fails in 2.4 <#attempt> Ignored but logged in 2.3: ${s?matches('broken', 'f')?string} == false <#recover> Fails in 2.4 ${"foobar"?replace("foo", "FOO")} == FOObar ${"Foobar"?replace("foo", "FOO", "")} == Foobar ${"Foobar"?replace("foo", "FOO", "i")} == FOObar ${"FoobarfOO"?replace("foo", "FOO", "i")} == FOObarFOO ${"FoobarfOO"?replace("foo", "FOO", "if")} == FOObarfOO ${"FoobarfOO"?replace("foo", "FOO", "fi")} == FOObarfOO ${"Foobar"?replace("foo", "FOO", "r")} == Foobar ${"Foobar"?replace("foo", "FOO", "ri")} == FOObar ${"FoobarfOO"?replace("foo", "FOO", "ri")} == FOObarFOO ${"FoobarfOO"?replace("foo", "FOO", "rif")} == FOObarfOO ${"FoobarfOO"?replace("foo", "FOO", "fri")} == FOObarfOO ${"foobar"?replace("fo+", "FOO")} == foobar ${"foobar"?replace("fo+", "FOO", "")} == foobar ${"foobar"?replace("fo+", "FOO", "r")} == FOObar ${"foobarfOo"?replace("fo+", "FOO", "ri")} == FOObarFOO ${"foobarfOo"?replace("fo+", "FOO", "rif")} == FOObarfOo <#attempt> Ignored but logged in 2.3: ${"foobar"?replace("foo", "FOO", "c")} <#recover> Fails in 2.4 <#macro dumpList xs>[<#list xs as x>${x}<#if x_has_next>, ] <@dumpList "fooXbarxbaaz"?split("X") /> == [foo, barxbaaz] <@dumpList "fooXbarxbaaz"?split("X", "") /> == [foo, barxbaaz] <@dumpList "fooXbarxbaaz"?split("X", "i") /> == [foo, bar, baaz] <@dumpList "fooXbarxbaaz"?split("X", "r") /> == [foo, barxbaaz] <@dumpList "fooXbarxbaaz"?split("X", "ri") /> == [foo, bar, baaz] <@dumpList "fooXXbarxxbaaz"?split("X+", "i") /> == [fooXXbarxxbaaz] <@dumpList "fooXXbarxxbaaz"?split("X+", "ri") /> == [foo, bar, baaz] libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-numericalcast.txt0000644000175000017500000000257611723544471030560 0ustar ebourgebourg<#ftl> <#setting locale="en_US"> <#setting number_format="0.#########"> <#assign testlist= [ 0, 1, -1, 0.5, 1.5, -0.5, -1.5, 0.25, -0.25, 1.75, -1.75, 1.01, -1.01, 0.01, -0.01, 127, 128, -127, -128, 32767, 32768, -32767, -32768, 2147483647, 2147483648, -2147483647, -2147483648, 4294967295, 4294967296, -4294967295, -4294967296, 2147483647.1, 2147483648.1, -2147483647.1, -2147483648.1, 4294967295.1, 4294967296.1, -4294967295.1, -4294967296.1 2147483647.5, 2147483648.5, -2147483647.5, -2147483648.5, 4294967295.5, 4294967296.5, -4294967295.5, -4294967296.5 ] /> ?int: <#list testlist as result> ${result}?int=${result?int} ?double <#list testlist as result> ${result}?double=${result?double} ?long <#list testlist as result> ${result}?long=${result?long} ?long from date ${"2011-05-08 18:00:15 GMT"?date("yyyy-MM-dd HH:mm:ss z")?long} = 1304877615000 ?float <#list testlist as result> ${result}?float=${result?float} ?byte <#list testlist as result> ${result}?byte=${result?byte} ?short <#list testlist as result> ${result}?short=${result?short} ?floor <#list testlist as result> ${result}?floor=${result?floor} ?ceiling <#list testlist as result> ${result}?ceiling=${result?ceiling} ?round <#list testlist as result> ${result}?round=${result?round} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-typebuiltins.txt0000644000175000017500000000122711723544472030452 0ustar ebourgebourgStNuBoMeTaMaHaHxSeCoLiInDiNo <#foreach x in [ "a", 1, false, testmethod, testmacro, html_escape, {"a":1}, [1], testcollection, testnode ]> <#if x?is_string>1<#else>0 <#if x?is_number>1<#else>0 <#if x?is_boolean>1<#else>0 <#if x?is_method>1<#else>0 <#if x?is_macro>1<#else>0 <#if x?is_transform>1<#else>0 <#if x?is_hash>1<#else>0 <#if x?is_hash_ex>1<#else>0 <#if x?is_sequence>1<#else>0 <#if x?is_collection>1<#else>0 <#if x?is_enumerable>1<#else>0 <#if x?is_indexable>1<#else>0 <#if x?is_directive>1<#else>0 <#if x?is_node>1<#else>0 <#macro testmacro> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-varargs.txt0000644000175000017500000000136311723544470027363 0ustar ebourgebourg<#setting number_format="#"> ${m.bar()} == 0 ${m.bar([])} == 0 ${m.bar(11)} == 11 ${m.bar(null, 11)} == 11 ${m.bar(11, 22)} == 1122 ${m.bar(11.6, 22.4)} == 1122 ${m.bar(11, 22, 33)} == 112233 ${m.bar([11, 22, 33])} == 112233 ${m.bar2(11, [22, 33, 44])} == -22334411 ${m.bar2(11, 22, 33)} == -223311 ${m.bar2(11, 22)} == -2211 ${m.bar2(11)} == -11 ${m.overloaded()} == 0 ${m.overloaded(11)} == -11 ${m.overloaded(11, 22)} == 1122 ${m.overloaded(11, 22, 33)} == -112233 ${m.overloaded(11, 22, 33, 44)} == -11223344 ${m.overloaded([11, 22, 33, 44, 55])} == -1122334455 ${m.overloaded(11, 22)} == 1122 ${m.overloaded([11, 22])} == -1122 ${m.noVarArgs("string", true, 123, 1000000?number_to_date)} == string, true, 123, 1000000 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-strictinheader_inc2.html0000644000175000017500000000002311723544472031760 0ustar ebourgebourg ${x}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-helloworld.html0000644000175000017500000000026111723544471030213 0ustar ebourgebourg FreeMarker: Exec Model Test

A simple test follows:

${exec( "java freemarker.testcase.HelloWorld" )}

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-stringbuiltins2.txt0000644000175000017500000000640011723544471031056 0ustar ebourgebourg-- <#assign s = "abbcdbb"> ${s?index_of("bb")} = 1 ${s?index_of("bb", 2)} = 5 ${s?index_of("")} = 0 -- ${s?last_index_of("bb")} = 5 ${s?last_index_of("bb", 4)} = 1 ${s?last_index_of("")} = ${s?length} -- ${s?starts_with("abb")?string} = true ${s?starts_with("bb")?string} = false ${s?starts_with("")?string} = true -- ${s?ends_with("dbb")?string} = true ${s?ends_with("cbb")?string} = false ${s?ends_with("")?string} = true -- ${s?contains("abb")?string} = true ${s?contains("bcd")?string} = true ${s?contains("dbb")?string} = true ${s?contains("bbx")?string} = false ${s?contains("")?string} = true -- [${s?chop_linebreak}] = [abbcdbb] [${"qwe\n"?chop_linebreak}] = [qwe] [${"qwe\r"?chop_linebreak}] = [qwe] [${"qwe\r\n"?chop_linebreak}] = [qwe] [${"qwe\r\n\r\n"?chop_linebreak}] = [qwe ] [${"qwe\n\n"?chop_linebreak}] = [qwe ] -- [${s?replace("A", "-")}] = [abbcdbb] [${s?replace("c", "-")}] = [abb-dbb] [${s?replace("bb", "-=*")}] = [a-=*cd-=*] -- <#assign ls = s?split("b")> <#list ls as i>[${i}] == [a][][cd][][] <#list "--die--maggots--!"?split("--") as i>[${i}] == [][die][maggots][!] <#list "Die maggots!"?split("--") as i>[${i}] == [Die maggots!] -- [${""?left_pad(5)}] [${"a"?left_pad(5)}] [${"ab"?left_pad(5)}] [${"abc"?left_pad(5)}] [${"abcd"?left_pad(5)}] [${"abcde"?left_pad(5)}] [${"abcdef"?left_pad(5)}] [${"abcdefg"?left_pad(5)}] [${"abcdefgh"?left_pad(5)}] [${""?left_pad(5, "-")}] [${"a"?left_pad(5, "-")}] [${"ab"?left_pad(5, "-")}] [${"abc"?left_pad(5, "-")}] [${"abcd"?left_pad(5, "-")}] [${"abcde"?left_pad(5, "-")}] [${"abcdef"?left_pad(5, "-")}] [${"abcdefg"?left_pad(5, "-")}] [${"abcdefgh"?left_pad(5, "-")}] [${""?left_pad(8, ".oO")}] [${"a"?left_pad(8, ".oO")}] [${"ab"?left_pad(8, ".oO")}] [${"abc"?left_pad(8, ".oO")}] [${"abcd"?left_pad(8, ".oO")}] [${"abcde"?left_pad(8, ".oO")}] [${"abcdef"?left_pad(8, ".oO")}] [${"abcdefg"?left_pad(8, ".oO")}] [${"abcdefgh"?left_pad(8, ".oO")}] [${"abcdefghi"?left_pad(8, ".oO")}] [${"abcdefghij"?left_pad(8, ".oO")}] [${""?left_pad(0, r"/\_")}] [${""?left_pad(1, r"/\_")}] [${""?left_pad(2, r"/\_")}] [${""?left_pad(3, r"/\_")}] [${""?left_pad(4, r"/\_")}] [${""?left_pad(5, r"/\_")}] [${""?left_pad(6, r"/\_")}] [${""?left_pad(7, r"/\_")}] -- [${""?right_pad(5)}] [${"a"?right_pad(5)}] [${"ab"?right_pad(5)}] [${"abc"?right_pad(5)}] [${"abcd"?right_pad(5)}] [${"abcde"?right_pad(5)}] [${"abcdef"?right_pad(5)}] [${"abcdefg"?right_pad(5)}] [${"abcdefgh"?right_pad(5)}] [${""?right_pad(5, "-")}] [${"a"?right_pad(5, "-")}] [${"ab"?right_pad(5, "-")}] [${"abc"?right_pad(5, "-")}] [${"abcd"?right_pad(5, "-")}] [${"abcde"?right_pad(5, "-")}] [${"abcdef"?right_pad(5, "-")}] [${"abcdefg"?right_pad(5, "-")}] [${"abcdefgh"?right_pad(5, "-")}] [${""?right_pad(8, ".oO")}] [${"a"?right_pad(8, ".oO")}] [${"ab"?right_pad(8, ".oO")}] [${"abc"?right_pad(8, ".oO")}] [${"abcd"?right_pad(8, ".oO")}] [${"abcde"?right_pad(8, ".oO")}] [${"abcdef"?right_pad(8, ".oO")}] [${"abcdefg"?right_pad(8, ".oO")}] [${"abcdefgh"?right_pad(8, ".oO")}] [${"abcdefghi"?right_pad(8, ".oO")}] [${"abcdefghij"?right_pad(8, ".oO")}] [${""?right_pad(0, r"/\_")}] [${""?right_pad(1, r"/\_")}] [${""?right_pad(2, r"/\_")}] [${""?right_pad(3, r"/\_")}] [${""?right_pad(4, r"/\_")}] [${""?right_pad(5, r"/\_")}] [${""?right_pad(6, r"/\_")}] [${""?right_pad(7, r"/\_")}]libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-include.html0000644000175000017500000000070611723544467027474 0ustar ebourgebourg FreeMarker: Include Instruction Test

A simple test follows:

${message} <#if message?exists>

Message exists!

Test normal includes:

<#include "test-included.html"> ${foo} ${nestedMessage}

Test unparsed includes:

<#include "test-included.html" parse=false> <@twice> Kilroy

Test subdir includes:

<#include "subdir/test-include-subdir.html"> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-bean-maps.html0000644000175000017500000000134711723544471027711 0ustar ebourgebourg[#ftl] [#macro test hash desc] ${desc} (${hash?size}): [#list hash?keys?sort as key] ${key}[#list 0 .. (16 - key?length) as x] [/#list]: [@print value=hash[key]/] [/#list] [/#macro] [#macro print value="DEBUGME"] [#if value?is_number || value?is_string] ${value}[#t] [#elseif value?is_boolean] [#if value]true[#else]false[/#if][#t] [#else] UNKNOWN[#t] [/#if] [/#macro] [@test hash=m1 desc="properties only, shadow"/] [@test hash=m2 desc="properties only"/] [@test hash=m3 desc="nothing, shadow"/] [@test hash=m4 desc="nothing"/] [@test hash=m5 desc="all, shadow"/] [@test hash=m6 desc="all"/] [@test hash=m7 desc="simple map mode"/] String concatenation: ${s1 + s2} ${s3 + s4} ${s1 + s3} ${s2 + s4} libfreemarker-java-2.3.19.orig/src/freemarker/testcase/template/test-new-unrestricted.txt0000644000175000017500000000021711723544471031216 0ustar ebourgebourg${"freemarker.testcase.models.NewTestModel"?new("works")} ${"freemarker.template.utility.ObjectConstructor"?new()("java.lang.String", "works")}libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/0000755000175000017500000000000012164627123024315 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-recover.ftl0000644000175000017500000000114011723544470027445 0ustar ebourgebourg Hello, World Well, that did not work. Here is the error: Expression undefined is undefined on line 8, column 47 in test-recover.ftl. Now we nest another attempt/recover here: Oops: Expression sequence[1] is undefined on line 13, column 6 in test-recover.ftl. Remember, freeMarker sequences are zero-based! Hello, World Now we output the current error message: Expression undefined is undefined on line 8, column 47 in test-recover.ftl. The template is not currently available The included template has a problem: Expression undefined_variable is undefined on line 1, column 3 in undefined.ftl. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-xmlns4.html0000644000175000017500000000037511723544472027417 0ustar ebourgebourg Test Book

Test Book

Ch1

p1.1

p1.2

p1.3

Ch2

p2.1

p2.2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-wstrim.txt0000644000175000017500000000037111723544471027365 0ustar ebourgebourgLB LB LB LB IB IC1 IC2C1C2 ICS CS1 CS2 C3C1C2 B B C1CB C1 C2 ICB IC ICB ICCB -- LB LB LB LB IB IC1 IC2C1C2 ICS CS1 CS2 C3C1C2 B B C1CB C1 C2 ICB IC ICB ICCB -- IB IC1C2 IB 12 --- 1 23 4 5 6 --- a bc --- foo --- foo libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-stringbuiltins.txt0000644000175000017500000000416111723544467031126 0ustar ebourgebourgFreeMarker: Encoding string built-in tests cap_first: DieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} uncap_first: dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} uncap_first:blah capitalize: Diebugsdie! * Vazzze 123456 --cdc-- --<<--@ X ${"kigyo"?upper_case} html: dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} length: 71 lower_case: diebugsdie! * vazzze 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} rtf: dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x $\{"kigyo"?upper_case\} trim: dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} trim2: foo bar trim3: foo bar trim4: foo bar upper_case: DIEBUGSDIE! * VAZZZE 123456 --CDC-- --<<--@ X ${"KIGYO"?UPPER_CASE} xml: dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x ${"kigyo"?upper_case} xhtml: "Blah's is > 1 & < 2" word_list: - dieBugsDie! - * - vazzZE - 123456 - --cdc-- - --<<--@ - x - ${"kigyo"?upper_case} interpret: dieBugsDie! * vazzZE 123456 --cdc-- --<<--@ x KIGYO number: -122,35 default constructor 1 xxx xxx:yyy In The Sacred, Holy beginning, God created The Sacred, Holy Heavens and The Sacred, Holy Earth. In the very beginning, God created the Heavens and The Earth. |I|n| |t|h|e| |b|e|g|i|n|n|i|n|g|,| |G|o|d| |c|r|e|a|t|e|d| |t|h|e| |H|e|a|v|e|n|s| |a|n|d| |T|h|e| |E|a|r|t|h|.| |In the beginning, God created the Heavens and The Earth. In the beginning, God created the sky and The Earth. matches the beginning the sacred beginning the Heavens the sacred Heavens The Earth The sacred Earth In the beginning, God created the Heavens and The Earth. beginning the Heavens and The Earth. foo bar baz foobar FOOBAR [a] = [a] [a\\'x'\nb] = [a\\'x'\nb] [\u0001\u001a ] = [\u0001\u001a ] [a] = [a] [a\\\'x\'\nb] = [a\\\'x\'\nb] [\x01\x1A ] = [\x01\x1A ] [a] = [a] [a\\'x'\nb] = [a\\'x'\nb] [\u0001\u001A ] = [\u0001\u001A ] [\n\r\t\f\b\"] = [\n\r\t\f\b\"] [/] = [/] [a/b] = [a/b] [<\/script>] = [<\/script>] []]\u003E] = []]\u003E] libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-import.txt0000644000175000017500000000046111723544470027351 0ustar ebourgebourg-- -- jsmith@acme.com Test bar. Email: jsmith@acme.com jsmith@acme.com Test bar. Email: jsmith@acme.com Email in the root: jsmith@other1.com jsmith@other2.com Test bar. Email: jsmith@other2.com Email in the root: jsmith@other1.com jsmith@other2.com jsmith@other3.com foobarfoobarlibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-arithmetic.html0000644000175000017500000000055511723544472030323 0ustar ebourgebourg FreeMarker: Arithmetic Test

A simple test follows:

Perform a number assignment:

3.234 2.00 0.6172500000000000000000000000000000000000 1.620089104901 1.6201

Display a number with at least 3 digits after the decimal point

1234.000

Now use numbers in assignment

1257.77 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-encodingbuiltins.txt0000644000175000017500000000106711723544471031403 0ustar ebourgebourgFreeMarker: Encoding built-in tests html: [&<>"'{}\a/] xml: [&<>"'{}\a/] xhtml: [&<>"'{}\a/] rtf: [&<>"'\{\}\\a/] html: [a&a<a>a"a'a{a}a\] xml: [a&a<a>a"a'a{a}a\] xhtml: [a&a<a>a"a'a{a}a\] rtf: [a&aa"a'a\{a\}a\\] html: [<<<<<] xml: [<<<<<] xhtml: [<<<<<] rtf: [\{\{\{\{\{] html: [] xml: [] xhtml: [] rtf: [] html: [a] xml: [a] xhtml: [a] rtf: [a] html: [&] xml: [&] xhtml: [&] rtf: [\{]libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-new-allowsnothing.txt0000644000175000017500000000000511723544470031510 0ustar ebourgebourgfailslibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-exception.html0000644000175000017500000000224311723544472030164 0ustar ebourgebourg FreeMarker: Exception Test

A simple test follows:

Hello, world!
freemarker.template.TemplateModelException: Throwing from ExceptionModel! at freemarker.testcase.models.ExceptionModel.getAsString(ExceptionModel.java:57) at freemarker.template.compiler.Expression.getStringValue(Expression.java:65) at freemarker.template.compiler.DollarVariable.process(DollarVariable.java:62) at freemarker.template.compiler.NestedTemplateElements.process(NestedTemplateElements.java:76) at freemarker.template.Template.process(Template.java:266) at freemarker.template.Template.process(Template.java:289) at freemarker.testcase.TestException.runTest(TestException.java:91) at junit.framework.TestCase.runBare(TestCase.java:140) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:131) at junit.framework.TestSuite.runTest(TestSuite.java:173) at junit.framework.TestSuite.run(TestSuite.java:168) at junit.swingui.TestRunner$17.run(TestRunner.java:644) libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-stringbimethods.txt0000644000175000017500000000007511723544470031245 0ustar ebourgebourg3.00 3.00 --- de true false yes no igen nem 0.0 1.0 true truelibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-xmlns3.html0000644000175000017500000000037511723544471027415 0ustar ebourgebourg Test Book

Test Book

Ch1

p1.1

p1.2

p1.3

Ch2

p2.1

p2.2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-charsetinheader.html0000644000175000017500000000017711723544472031323 0ustar ebourgebourg éáőű õÕûÛ Å‘ÅűŰ libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-number-to-date.txt0000644000175000017500000000070511723544472030665 0ustar ebourgebourg2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z 2011-05-16 == 2011-05-16 19:47:55.54Z == 19:47:55.54Z 2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z 2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z 2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z 2011-05-16T19:47:55.54Z == 2011-05-16T19:47:55.54Z 1970-01-01T00:00:01Z == 1970-01-01T00:00:01Z 1970-01-01T00:00:01Z == 1970-01-01T00:00:01Z 1970-01-01T00:00:00Z == 1970-01-01T00:00:00Z failed libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-exception2.html0000644000175000017500000000233411723544470030245 0ustar ebourgebourg FreeMarker: Exception Test

A simple test follows:

Hello, world!

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-xml.html0000644000175000017500000000162411723544471026767 0ustar ebourgebourg firstPi customKey="something" secondPi secondPiData 2 p customKey="something" text1text2 text1 text1text2 a1 v2 rootroot root root e1 e11 e12 e2 e11 e12 root root e1 root e1 e11 root e1 e12 root e2 root e2 e11 root e2 e12 cdata-section2<& cdata-section2<& libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-variables.html0000644000175000017500000000103411723544471030132 0ustar ebourgebourg FreeMarker: Variable Test

A simple test follows:

Hello, world!

Now get into variable nesting:

My message.

My message.

My message.

My message.

My message.

My message.

My message.

My message.

More deep nesting...

My message.

one

one

Nesting inside nesting...

two

two

two

two

Test underscores...

out

out

SAVE libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-escapes.txt0000644000175000017500000000060411723544470027461 0ustar ebourgebourga b c a b c a 1 a b c <&> &lt;&amp;&gt; <&> --- = = <MOOO> = <MOOO> = <MOOO> = <MOOO> = = <Mooo> = <Mooo> = <Mooo> = <Mooo> = = red green blue ---libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-switch.html0000644000175000017500000000146111723544467027474 0ustar ebourgebourg FreeMarker: Switch-Case Test

Here we iterate over a list of animals.

Animal is: aardvark.
This is the HTML for other animals.

Animal is: kiwi.
This is the HTML for the user's favorite animal.

Animal is: gecko.
This is the HTML for small animals.

Animal is: cat.
This is the HTML for other animals.

Animal is: dog.
This is the HTML for other animals.

Animal is: elephant.
This is the HTML for large animals.

Animal is: squirrel.
This is the HTML for small animals.

Animal is: zebra.
This is the HTML for a large stripey animal. This is the HTML for large animals.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-lastcharacter.html0000644000175000017500000000025111723544470031001 0ustar ebourgebourg FreeMarker: Last Character Test

A simple test follows:

13 ELLO, WORLD! message: Hello, Worl libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-varlayers.txt0000644000175000017500000000033711723544472030053 0ustar ebourgebourg 1 = 1 2 = 2 3 = 3 4 = 4 = 4 5 = 5 = 5 6 but 4 = 4 7 = 7 = 7 Invisiblity test 1.: passed Invisiblity test 2.: passed Invisiblity test 3.: passed -- 1 = 1 2 = 2 3 = 3 4 = 4 = 4 = 4 5 6 == 6 7 == 7 == 7 -- libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-transformation.html0000644000175000017500000000312311723544470031230 0ustar ebourgebourg FreeMarker: Transformation Test

A simple test follows:

Hello, world!

<p>Hello, world!</p>

Now try the Utility package:

Utility transformations

<p>Utility transformations</p>

Now some nested transforms:

This tests the compress transformation

<p >This tests the compress transformation</p ><p >This tests the compress transformation</p >

Now try method and transform interactions:

<p>This isn't a valid XML string.</p> <p>This isn't a valid HTML string.</p>

A more advanced interaction involves getting a TemplateMethodModel to initialise a TemplateTransformModel, as follow:

Comment: This is a comment A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish & Chips.

Comment: This is a second comment A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish & Chips.

Comment: This is a third comment A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags:

Fish &amp; Chips.

Comment: Utility transformations A test string containing quotes: "This isn't a test". A test string containing amps: Fish & Chips. A test string containing tags: <p>Fish & Chips.</p> I saw the python. It was cool. 4 5 2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-stringliteral.html0000644000175000017500000000134411723544470031050 0ustar ebourgebourg FreeMarker: String literal test

A simple test follows:

Hello, World!

[] = []
[a] = [a]
[abcdef] = [abcdef]
["] = ["]
["""] = ["""]
[a"] = [a"]
["a] = ["a]
[a"b] = [a"b]
[a b] = [a b]
['] = [']
[a'a] = [a'a]
["'  <&>]
[ A]
[śzś]
[ČzČ]

[] = []
[a] = [a]
[abcdef] = [abcdef]
["] = ["]
["""] = ["""]
[a"] = [a"]
["a] = ["a]
[a"b] = [a"b]
[a b] = [a b]
['] = [']
[a'a] = [a'a]
["'  <&>]
[ A]
[śzś]
[ČzČ]
libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-hashconcat.ftl0000644000175000017500000000131411723544471030117 0ustar ebourgebourg a: a = 1 b = 2 c = 3 X = 4 --- 1 2 3 4 --- B: d = 10 e = 20 f = 30 X = 40 --- 10 20 30 40 --- a + B: a = 1 b = 2 c = 3 X = 40 d = 10 e = 20 f = 30 --- 1 2 3 40 10 20 30 --- B + a: d = 10 e = 20 f = 30 X = 4 a = 1 b = 2 c = 3 --- 10 20 30 4 1 2 3 --- a + a: a = 1 b = 2 c = 3 X = 4 --- 1 2 3 4 --- {} + a: a = 1 b = 2 c = 3 X = 4 --- 1 2 3 4 --- a + {}: a = 1 b = 2 c = 3 X = 4 --- 1 2 3 4 --- {} + {}: --- --- a + b + {} + b + {} + a: a = 1 b = 2 c = 3 X = 4 d = 10 e = 20 f = 30 --- 1 2 3 4 10 20 30 --- libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-xmlns5.txt0000644000175000017500000000012211723544470027257 0ustar ebourgebourgNo NS = No NS x NS = x NS y NS = y NS x NS = x NS No NS = No NS - = - - = - - = - libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-numberformat.txt0000644000175000017500000000021711723544471030540 0ustar ebourgebourg1 1 1 234 567,89 1234567.886 1,00 1 1234567,89 1234567.886 1 1 1.000000000000001 0.0000000000000001 -0.0000000000000001 1 0.0000000000000001 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-newlines2.html0000644000175000017500000000022711723544470030072 0ustar ebourgebourg FreeMarker: Newlines the Second Test

A simple test follows:

Hello, world!

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-listliteral.html0000644000175000017500000000134411723544470030515 0ustar ebourgebourg FreeMarker: List Literal Test

A simple test follows:

Hello, world!

Now perform a list assignment:

The list contains 5 items.

test1

test23

test45

Hello, world!

hello

Now update the assignment and repeat:

test1

test23

test45

Hello, world!

hello

Now reassign the list and repeat:

bar

Temporary

test1

test23

Silly, but necessary tests, for one and zero element lists:

Hello, world

Zero item test:

Dumb test for number literals -- these weren't working as expected:

1

2

3

5

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-noparse.html0000644000175000017500000000125111723544470027631 0ustar ebourgebourg FreeMarker: NoParse Test A simple test follows: ${message} A more rigorous test, showing that we're not faking it: ${message@#$%&}

Message exists! ...and even generates output! Nested statements are ok, too.

Here's another edge case, this time, trying to output a <noparse> inside another <noparse> This is what the noparse instruction looks like: This part of the template wont be parsed by the FreeMarker parser. Instead, it will be treated as verbatim text information, and output as such. The rest of the template appears here. Simple. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-new-safer.txt0000644000175000017500000000001311723544471027720 0ustar ebourgebourgworks failslibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-wsstripinheader.txt0000644000175000017500000000001011723544471031241 0ustar ebourgebourga b a blibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-newlines1.html0000644000175000017500000000021211723544467030071 0ustar ebourgebourg FreeMarker: Newlines Test

A simple test follows:

Hello, world!

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-xmlfragment.txt0000644000175000017500000000022611723544471030363 0ustar ebourgebourgb = b @document = @document @document = @document C<>&"']]> = C<>&"']]>
C<>&"']]>libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-defaultxmlns1.txt0000644000175000017500000000007111723544471030624 0ustar ebourgebourgNo NS = No NS x NS = x NS y NS = y NS x NS = x NS true libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-new-defaultresolver.txt0000644000175000017500000000001311723544470032025 0ustar ebourgebourgworks workslibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-logging.html0000644000175000017500000000032111723544467027613 0ustar ebourgebourg FreeMarker: Logging Test A simple test follows: ERROR [freemarker.template.Template]: message is not a TemplateHashModel, it's a freemarker.template.SimpleScalar. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-local.html0000644000175000017500000000024411723544471027256 0ustar ebourgebourg FreeMarker: Localization Test

A simple test follows:

Hello, world!

G'day, mate!

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-root.html0000644000175000017500000000067111723544471027153 0ustar ebourgebourg FreeMarker: Root Lookup Test

A simple test follows:

Hello, world!

Access the same variable via the root variable (dot syntax):

Hello, world!

Access the same variable via the root variable (bracket syntax):

Hello, world!

Ensure that root lookups are unaffected by local variables:

Hello, world! Hello, world! Part Deux libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-comparisons.html0000644000175000017500000000355411723544471030530 0ustar ebourgebourg FreeMarker: Numeric Operations Test

A simple test follows:

Hello, world!

Start with the increment operator:

a1 = 0

a1 = 1

a1 = 2

Now the decrement operator:

a2 = 5

a2 = 4

a2 = 3

a2 = 2

a2 = 1

a2 = 0

a2 = -1

Now the add operator:

op1 = 5, op2 = 3, op3 = 8

op3 = 11

And the subtract operator:

op1 = 5, op2 = 3, op3 = 2

op3 = -1

The comparison operators:

Item is: 0

Item is less than five.

Item is less than or equals to seven.

Item is: 1

Item is less than five.

Item is less than or equals to seven.

Item is: 2

Item is less than five.

Item is less than or equals to seven.

Item is: 3

Item is less than five.

Item is less than or equals to seven.

Item is greater than two.

Item is: 4

Item is less than five.

Item is less than or equals to seven.

Item is greater than two.

Item is: 5

Item is less than or equals to seven.

Item is greater than two.

Item is: 6

Item is less than or equals to seven.

Item is greater than two.

Item is: 7

Item is less than or equals to seven.

Item is greater than two.

Item is: 8

Item is greater than two.

Item is: 9

Item is greater than two.

Item is: 10

Item is greater than two.

Item is greater than or equal to ten.

Item is: 11

Item is greater than two.

Item is greater than or equal to ten.

Item is: 12

Item is greater than two.

Item is greater than or equal to ten.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-boolean.html0000644000175000017500000000170211723544471027603 0ustar ebourgebourg FreeMarker: Boolean Values Test

A simple test follows:

Hello, world!

Now perform scalar boolean tests:

b is true.

This makes sense.

boolean3 succeeded.

boolean4 succeeded.

boolean4 || boolean5 succeeded.

boolean5 || boolean4 || boolean5 succeeded.

boolean4 && boolean5 failed.

Now test list models:

list1 succeeded.

list2 succeeded.

Test hash models:

hash1 succeeded: Hello, world.

hash2 succeeded.

Test not operator:

Not boolean1 succeeded

Not boolean1 succeeded

Not boolean2 failed

Not boolean2 failed

Message is "Hello, world!"

Message is "Hello, world!"

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-macro.html0000644000175000017500000000004411723544470027262 0ustar ebourgebourg1 1 2 2 4 m3 with d="4" Failed! libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-exception3.html0000644000175000017500000000016711723544470030250 0ustar ebourgebourg Template Compilation Error: Identifier expected at line 10. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-include2.html0000644000175000017500000000200311723544470027663 0ustar ebourgebourg FreeMarker: Include Instruction Test

A simple test follows:

Hello, world!

Message exists!

Test normal includes:

freemarker.template.TemplateException: Template "../bogus/test-included.html" not found in cache. at freemarker.template.compiler.Include.process(Include.java:90) at freemarker.template.compiler.NestedTemplateElements.process(NestedTemplateElements.java:70) at freemarker.template.Template.process(Template.java:363) at freemarker.testcase.TestInclude2.runTest(TestInclude2.java:89) at junit.framework.TestCase.runBare(TestCase.java:140) at junit.framework.TestResult$1.protect(TestResult.java:106) at junit.framework.TestResult.runProtected(TestResult.java:124) at junit.framework.TestResult.run(TestResult.java:109) at junit.framework.TestCase.run(TestCase.java:131) at junit.framework.TestSuite.runTest(TestSuite.java:173) at junit.framework.TestSuite.run(TestSuite.java:168) at junit.swingui.TestRunner$17.run(TestRunner.java:644) libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-numberliteral.html0000644000175000017500000000132411723544471031031 0ustar ebourgebourg FreeMarker: Number Literal Test

A simple test follows:

Hello, world!

Now perform a number assignment:

1,3 My number is: 1,8 My float is: 1.800000 The int part is: 1 1.83

Now use numbers in assignment

6 8

Try numbers in tests

MyMessage is not 152, its: 8. 5)> MyMessage is greater than five. Now for numbers in dynamic keys:

one three

Numbers in hashes:

twelve twelve twelve

Numbers in method calls:

Single argument value is: 1 Single argument value is: 1 Single argument value is: 12 Single argument value is: 3 Single argument value is: 3 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-exthash.html0000644000175000017500000000102311723544471027624 0ustar ebourgebourg FreeMarker: Extended Hash Test

A simple test follows:

Hello, world!

A hash set of 8 animals follows:

elephant, cat, zebra, dog, aardvark, kiwi, squirrel, gecko.

The first animal is an elephant, and the last is a gecko.

A hash set of 8 digits follows:

six, four, eight, five, one, two, seven, three.

The zebra number is eight.

The end.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-outputencoding1.txt0000644000175000017500000000022011723544471031161 0ustar ebourgebourgOutput charset: UTF-8 URL escaping charset: undefined a%FE%FF%00%2F%00%25b a%FE%FF%00%2F%00%25b a%2F%25b a%2F%25b a%FE%FF%00%2F%00%25b a%2F%25blibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-extlist.html0000644000175000017500000000055411723544471027664 0ustar ebourgebourg FreeMarker: Extended List Test

A simple test follows:

Hello, world!

A list of 8 animals follows:

aardvark, kiwi, gecko, cat, dog, elephant, squirrel, zebra.

The first animal is an aardvark, and the last is a zebra.

The end.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-identifier.html0000644000175000017500000000044111723544472030306 0ustar ebourgebourg FreeMarker: Identifier Test

A simple test follows:

Hello, world!

A tag inside a tag...

this is a test Blah This is a test libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-iso8601.txt0000644000175000017500000000646211723544471027160 0ustar ebourgebourg2010-05-15T20:38:05Z = 2010-05-15T20:38:05Z 2010-05-15T20:38:05.023Z = 2010-05-15T20:38:05.023Z 2010-05-15T20:38Z = 2010-05-15T20:38Z 2010-05-15T20Z = 2010-05-15T20Z 2010-05-15T20:38:05 = 2010-05-15T20:38:05 2010-05-15T20:38:05.023 = 2010-05-15T20:38:05.023 2010-05-15T20:38 = 2010-05-15T20:38 2010-05-15T20 = 2010-05-15T20 2010-05-15T22:38:05+02:00 = 2010-05-15T22:38:05+02:00 2010-05-15T22:38:05.023+02:00 = 2010-05-15T22:38:05.023+02:00 2010-05-15T22:38+02:00 = 2010-05-15T22:38+02:00 2010-05-15T22+02:00 = 2010-05-15T22+02:00 2010-05-15T22:38:05 = 2010-05-15T22:38:05 2010-05-15T22:38:05.023 = 2010-05-15T22:38:05.023 2010-05-15T22:38 = 2010-05-15T22:38 2010-05-15T22 = 2010-05-15T22 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 20:38:05Z = 20:38:05Z 20:38:05.023Z = 20:38:05.023Z 20:38Z = 20:38Z 20Z = 20Z 20:38:05 = 20:38:05 20:38:05.023 = 20:38:05.023 20:38 = 20:38 20 = 20 22:38:05+02:00 = 22:38:05+02:00 22:38:05.023+02:00 = 22:38:05.023+02:00 22:38+02:00 = 22:38+02:00 22+02:00 = 22+02:00 22:38:05 = 22:38:05 22:38:05.023 = 22:38:05.023 22:38 = 22:38 22 = 22 0600-01-01T23:59:59.123Z = 0600-01-01T23:59:59.123Z 2010-05-15T20:38:05Z = 2010-05-15T20:38:05Z 2010-05-15T20:38:05.023Z = 2010-05-15T20:38:05.023Z 2010-05-15T20:38Z = 2010-05-15T20:38Z 2010-05-15T20Z = 2010-05-15T20Z 2010-05-15T20:38:05 = 2010-05-15T20:38:05 2010-05-15T20:38:05.023 = 2010-05-15T20:38:05.023 2010-05-15T20:38 = 2010-05-15T20:38 2010-05-15T20 = 2010-05-15T20 2010-05-15T22:38:05+02:00 = 2010-05-15T22:38:05+02:00 2010-05-15T22:38:05.023+02:00 = 2010-05-15T22:38:05.023+02:00 2010-05-15T22:38+02:00 = 2010-05-15T22:38+02:00 2010-05-15T22+02:00 = 2010-05-15T22+02:00 2010-05-15T22:38:05 = 2010-05-15T22:38:05 2010-05-15T22:38:05.023 = 2010-05-15T22:38:05.023 2010-05-15T22:38 = 2010-05-15T22:38 2010-05-15T22 = 2010-05-15T22 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 2010-05-15 = 2010-05-15 20:38:05Z = 20:38:05Z 20:38:05.023Z = 20:38:05.023Z 20:38Z = 20:38Z 20Z = 20Z 20:38:05 = 20:38:05 20:38:05.023 = 20:38:05.023 20:38 = 20:38 20 = 20 22:38:05+02:00 = 22:38:05+02:00 22:38:05.023+02:00 = 22:38:05.023+02:00 22:38+02:00 = 22:38+02:00 22+02:00 = 22+02:00 22:38:05 = 22:38:05 22:38:05.023 = 22:38:05.023 22:38 = 22:38 22 = 22 2010-05-15T20:38:05Z = 2010-05-15T20:38:05Z 2010-05-15T22:38:05+02:00 = 2010-05-15T22:38:05+02:00 2010-05-15T22:38:05+02:00 = 2010-05-15T22:38:05+02:00 12:00:00.001Z = 12:00:00.001Z 12:00:00.01Z = 12:00:00.01Z 12:00:00.1Z = 12:00:00.1Z 12:00:00Z = 12:00:00Z 2010-05-15 = 2010-05-15 2010-05-14 = 2010-05-14 2010-05-15T00:00:00+02:30 = 2010-05-15T00:00:00+02:30 2010-05-09T16:00:00-04:00 = 2010-05-09T16:00:00-04:00 2010-01-01T15:00:00-05:00 = 2010-01-01T15:00:00-05:00 unrecognized time zone name libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-models.html0000644000175000017500000000357411723544467027465 0ustar ebourgebourg FreeMarker: Test of Multiple Model implementations

Let's begin with a simple model:

Hello, world!

Cool, now get into the first model. This implements a scalar, list, and hash as a single class. Let's try some tests...

MultiModel1 as a string!

Now as a list...

Model1 value: 0
Model1 value: 1
Model1 value: 2
Model1 value: 3
Model1 value: 4
Model1 value: 5
Model1 value: 6
Model1 value: 7
Model1 value: 8
Model1 value: 9
Model3 is alive!

Index into a list...

Model1 value: 1

List size is: Nasty!

List size is: Nasty!

Now, again, as a hash. First using dot notation, then using [] notation:

Selftest of a hash from MultiModel1

Selftest of a hash from MultiModel1

Now for the tricky stuff... use a model to index into another model...

selftest

Selftest of a hash from MultiModel1

self

Selftest of a hash from MultiModel1

Same thing, this time a List index...

0

Model1 value: 0

Model1 value: 1

Now, do the same recursively...

MultiModel1 as a string!

Model2 is alive!

Arguments are:
test

Arguments are:
MultiModel1 as a string!
Selftest of a hash from MultiModel1
Hello, world!

Does this really not work?

Model3 is alive!

Selftest from MultiModel3!

Hello world from MultiModel3!

(Again, with Hashes)

Model3 is alive!

Selftest from MultiModel3!

Model3 is alive!

Selftest from MultiModel3!

Selftest from MultiModel3!

As I suspected! (Manual on Expressions needs updating.)

Second test on list size

Key size, not the listSize method.

Key size, not the listSize method.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-hashliteral.html0000644000175000017500000000107311723544471030465 0ustar ebourgebourg FreeMarker: Hash Literal Test

A simple test follows:

Hello, world!

Now perform a hash assignment:

test23 Hello, world! hello all 1

Now update the assignment and repeat:

test23 Hello, world! hello all 1

Now reassign the list and repeat:

test23 Hello, world! 1 Temporary Temporary Temporary

Pathological case: zero item hash:

Hash of number literals:

2

Hash concatenation:

a => 1 b => 3 c => 4

Empty hash concatenation:

foo, bar libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-sequencebuiltins.txt0000644000175000017500000000772011723544471031427 0ustar ebourgebourgSize 0 Sorting scalars: ---------------- String order: - aardvark - Barbara - beetroot - whale - zeppelin First: aardvark Last: zeppelin Size 5 Numerical order: - -324 - -34 - 0 - 0.1 - 0.11 - 1 - 5 - 111 - 123 - 543 First: -324 Last: 543 Size 10 Date/time order: - 06:05 - 08:05 - 08:15 - 18:00 Boolean order: - false - false - true - true Sorting hashes: --------------- Order by name: - aardvark: 30 - Barbara: 53 - beetroot: 0.3 - whale: 2000 - zeppelin: -200 Order by weight: - zeppelin: -200 - beetroot: 0.3 - aardvark: 30 - Barbara: 53 - whale: 2000 Order by a.x.v: - aqweqw - dfgdf - qweqw - utyu Order by a.y, which is a date: - 1998-02-20 - 1999-01-20 - 1999-04-19 - 1999-04-20 Reverse: -------- Order by weight desc: - whale: 2000 - Barbara: 53 - aardvark: 30 - beetroot: 0.3 - zeppelin: -200 Order by weight desc desc: - zeppelin: -200 - beetroot: 0.3 - aardvark: 30 - Barbara: 53 - whale: 2000 Order by weight desc desc desc: - whale: 2000 - Barbara: 53 - aardvark: 30 - beetroot: 0.3 - zeppelin: -200 Contains: --------- True: true true true true true true true False: false false false false false false false False: false Index_of: --------- 0 = 0 1 = 1 2 = 2 6 = 6 0 = 0 1 = 1 2 = 2 -1 = -1 -1 = -1 -1 = -1 -1 = -1 -1 = -1 -1 = -1 -1 = -1 -1 = -1 Last_index_of: -------------- 6 = 6 1 = 1 2 = 2 7 = 7 -1 = -1 0 = 0 1 = 1 2 = 2 -1 = -1 Index_of and last_index_of with starting indices ------------------------------------------------ seq_index_of "Joe": 0 = 0 0 = 0 0 = 0 2 = 2 2 = 2 -1 = -1 -1 = -1 seq_last_index_of "Joe": -1 = -1 -1 = -1 0 = 0 0 = 0 2 = 2 2 = 2 2 = 2 seq_index_of "Susan": 3 = 3 3 = 3 3 = 3 3 = 3 3 = 3 3 = 3 -1 = -1 seq_last_index_of "Susan": -1 = -1 -1 = -1 -1 = -1 -1 = -1 -1 = -1 3 = 3 3 = 3 seq_index_of "a": 0 = 0 0 = 0 0 = 0 -1 = -1 -1 = -1 -1 = -1 -1 = -1 seq_index_of "b": 1 = 1 1 = 1 1 = 1 1 = 1 -1 = -1 -1 = -1 seq_index_of "c": 2 = 2 2 = 2 2 = 2 2 = 2 2 = 2 -1 = -1 seq_last_index_of "a": -1 = -1 -1 = -1 0 = 0 0 = 0 0 = 0 0 = 0 0 = 0 seq_last_index_of "b": -1 = -1 -1 = -1 -1 = -1 1 = 1 1 = 1 1 = 1 seq_last_index_of "c": -1 = -1 -1 = -1 -1 = -1 -1 = -1 2 = 2 2 = 2 Chunk ----- columns = 1, fill = NULL: Rows: 7 a <-- Columns: 1 b <-- Columns: 1 c <-- Columns: 1 d <-- Columns: 1 e <-- Columns: 1 f <-- Columns: 1 g <-- Columns: 1 columns = 2, fill = NULL: Rows: 4 a b <-- Columns: 2 c d <-- Columns: 2 e f <-- Columns: 2 g <-- Columns: 1 columns = 3, fill = NULL: Rows: 3 a b c <-- Columns: 3 d e f <-- Columns: 3 g <-- Columns: 1 columns = 4, fill = NULL: Rows: 2 a b c d <-- Columns: 4 e f g <-- Columns: 3 columns = 5, fill = NULL: Rows: 2 a b c d e <-- Columns: 5 f g <-- Columns: 2 columns = 10, fill = NULL: Rows: 1 a b c d e f g <-- Columns: 7 columns = 1, fill = -: Rows: 7 a <-- Columns: 1 b <-- Columns: 1 c <-- Columns: 1 d <-- Columns: 1 e <-- Columns: 1 f <-- Columns: 1 g <-- Columns: 1 columns = 2, fill = -: Rows: 4 a b <-- Columns: 2 c d <-- Columns: 2 e f <-- Columns: 2 g - <-- Columns: 2 columns = 3, fill = -: Rows: 3 a b c <-- Columns: 3 d e f <-- Columns: 3 g - - <-- Columns: 3 columns = 4, fill = -: Rows: 2 a b c d <-- Columns: 4 e f g - <-- Columns: 4 columns = 5, fill = -: Rows: 2 a b c d e <-- Columns: 5 f g - - - <-- Columns: 5 columns = 10, fill = -: Rows: 1 a b c d e f g - - - <-- Columns: 10 columns = 3, fill = NULL: Rows: 3 1 2 3 <-- Columns: 3 4 5 6 <-- Columns: 3 7 8 9 <-- Columns: 3 columns = 3, fill = -: Rows: 3 1 2 3 <-- Columns: 3 4 5 6 <-- Columns: 3 7 8 9 <-- Columns: 3 columns = 3, fill = NULL: Rows: 1 1 <-- Columns: 1 columns = 3, fill = -: Rows: 1 1 - - <-- Columns: 3 columns = 3, fill = NULL: Rows: 0 columns = 3, fill = -: Rows: 0 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-loopvar.txt0000644000175000017500000000072111723544470027520 0ustar ebourgebourg--- 2 - L1 1 - L2 1: 1; 2; 3; - L2 2: 1; 2; 3; * - L1 2 - L2 1: 1; 2; 3; - L2 2: 1; 2; 3; * - L1 3 - L2 1: 1; 2; 3; - L2 2: 1; 2; 3; * * 1 - L1 1 - L2 1: 1; 2; 3; - L2 2: 1; 2; 3; * - L1 2 - L2 1: 1; 2; 3; - L2 2: 1; 2; 3; * - L1 3 - L2 1: 1; 2; 3; - L2 2: 1; 2; 3; * * --- 1 0.5 2 1 3 1.5 4 2 Last! 123.4 ---libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-new-optin.txt0000644000175000017500000000007711723544471027763 0ustar ebourgebourgworks fails works works works fails works fails works workslibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-dateformat.html0000644000175000017500000000113711723544471030314 0ustar ebourgebourgNov 15, 2002 2:54:13 PM Nov 15, 2002 2:54:13 PM Nov 15, 2002 2:54:13 PM Nov 15, 2002 2:54:13 PM 11/15/02 2:54 PM Nov 15, 2002 2:54:13 PM November 15, 2002 2:54:13 PM GMT 11/15/02 2:54 PM 11/15/02 2:54:13 PM 11/15/02 2:54:13 PM GMT Nov 15, 2002 2:54 PM Nov 15, 2002 2:54:13 PM Nov 15, 2002 2:54:13 PM GMT November 15, 2002 2:54 PM November 15, 2002 2:54:13 PM November 15, 2002 2:54:13 PM GMT Nov 15, 2002 Nov 15, 2002 11/15/02 Nov 15, 2002 November 15, 2002 2:54:13 PM 2:54:13 PM 2:54 PM 2:54:13 PM 2:54:13 PM GMT 2002. november 15. 14:54:13 GMT Fri, 15 Nov 02002 14:54:13 GMT Fri, 15 Nov 02002 14:54:13 GMTlibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-compress.html0000644000175000017500000000102211723544470030011 0ustar ebourgebourg FreeMarker: Compress Test

A simple test follows:

Hello, world!

This is the same message, using the "compress" tag:

Hello, world!

This is the same message, using the "StandardCompress" transform model:

Hello, world!

This multi-line message should be compressed to a single line.

An example where the first character is not whitespace but the second character is:

x y

The end.

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-outputencoding3.txt0000644000175000017500000000026111723544470031167 0ustar ebourgebourgOutput charset: ISO-8859-1 URL escaping charset: UTF-16 UTF-16: a%FE%FF%00%2F%00%25b ISO-8859-1: a%2F%25b UTF-16: a%FE%FF%00%2F%00%25b ISO-8859-1: a%2F%25b ISO-8859-1: a%2F%25blibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-comment.html0000644000175000017500000000017311723544470027626 0ustar ebourgebourg FreeMarker: Comment Test

Message exists!

a b a b libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-wstripping.txt0000644000175000017500000000006711723544467030255 0ustar ebourgebourga b c d e2 f g x x x y y x y x y a x b x clibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-outputencoding2.txt0000644000175000017500000000054411723544472031174 0ustar ebourgebourgþÿOutput charset: UTF-16 URL escaping charset: undefined UTF-16: a%FE%FF%00%2F%00%25b ISO-8859-1: a%2F%25b UTF-16: a%FE%FF%00%2F%00%25b ISO-8859-1: a%2F%25b ISO-8859-1: a%2F%25b libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-nested1.txt0000644000175000017500000000033111723544470027376 0ustar ebourgebourg test 3/1: undefined undefined undefined test 3/2: undefined undefined undefined test 3/3: undefined undefined undefined test 3/1: Y X Count 1 test 3/2: Y X Count 2 test 3/3: Y X Count 3 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-strictinheader.html0000644000175000017500000000003211723544472031170 0ustar ebourgebourg1 34libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-precedence.html0000644000175000017500000000033611723544467030270 0ustar ebourgebourg FreeMarker: Operator Precedence Test @@@@@@@@@@@

##########

&&&&&&&&&&&

!!!!!!!!!!!

$$$$$$$$$$$ libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-function.html0000644000175000017500000000131311723544467030014 0ustar ebourgebourg FreeMarker: Function Test

A simple test follows:

Hello, world!

Now perform function tests:

Function is defined, now let's call it:

Home Kilroy was here.

Again, but with different parameters:

About Us Kilroy was here. Good.

A recursive function call:

0 1 2 3

Test "catch-all" macro parameter:

foo=a baz=[] foo=a baz=[bar=b] foo=a baz=[baz=c, bar=b] Hello World! Today is Monday. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-listiterators.html0000644000175000017500000000142511723544470031075 0ustar ebourgebourg FreeMarker: List Iterator Test

A simple test follows:

Hello, world!

Now iterate over a list:

one

two

three

four

five

Now iterate again:

0. one

1. two

2. three

3. four

4. five

Iterate over a list in a hash:

one

two

three

four

five

one

two

three

four

five

one

two

three

four

five

one

two

three

four

five

Now test the list and foreach keywords...

one

two

three

four

five

one

two

three

four

five

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-beans.html0000644000175000017500000000053711723544470027260 0ustar ebourgebourgarray-0 array-1 2 array-0 array-1 list-0 list-1 list-2 3 not empty list-0 value objValue foo-value hasfoo nobaz bar-value-0 bar-value-0 foo-value overloaded-int-1 overloaded-String-String Message 1974-11-14 static-method static-overloaded-int-1 static-overloaded-String-String static-final-field static-field ONEx TWOx THREEx true false false 42libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-interpret.html0000644000175000017500000000002511723544467030202 0ustar ebourgebourgabcdef abcdef abcdef libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-xmlns.html0000644000175000017500000000103011723544470027316 0ustar ebourgebourg Test Book Ch1 p1.1 p1.2 p1.3 Ch2 p2.1 p2.2 Test Book

Test Book

Ch1

p1.1

p1.2

p1.3

Ch2

p2.1

p2.2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-default.ftl0000644000175000017500000000005211723544471027426 0ustar ebourgebourgfoo luck 0 UNDEFINED is undefined. libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-specialvars.txt0000644000175000017500000000020611723544472030352 0ustar ebourgebourgen == en en_US == en_US utf-8 == utf-8 test-specialvars.txt == test-specialvars.txt iso-8859-1 == iso-8859-1 x == x true == truelibfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/string-builtins-regexps.txt0000644000175000017500000000275411723544470031701 0ustar ebourgebourgtrue == true true == true false == false true == true false == false true == true false == false true == true false == false false == false false == false true == true true == true true == true false == false false == false true == true true == true true == true true == true Lower 'c'-words: - coverage - considered Any 'c'-words: - Code - coverage - considered Lower line-last words: - coverage Any line-last words: - coverage - BROKEN Any last words: - BROKEN c-word with follower: - "Code without" Groups: "Code without", "Code", "without" - "coverage\nis" Groups: "coverage\nis", "coverage", "is" - "considered to" Groups: "considered to", "considered", "to" c-word with follower in the same line: - Code without - considered to Lower c-word with follower in the same line: - considered to Ignored but logged in 2.3: false == false Ignored but logged in 2.3: false == false FOObar == FOObar Foobar == Foobar FOObar == FOObar FOObarFOO == FOObarFOO FOObarfOO == FOObarfOO FOObarfOO == FOObarfOO Foobar == Foobar FOObar == FOObar FOObarFOO == FOObarFOO FOObarfOO == FOObarfOO FOObarfOO == FOObarfOO foobar == foobar foobar == foobar FOObar == FOObar FOObarFOO == FOObarFOO FOObarfOo == FOObarfOo Ignored but logged in 2.3: FOObar [foo, barxbaaz] == [foo, barxbaaz] [foo, barxbaaz] == [foo, barxbaaz] [foo, bar, baaz] == [foo, bar, baaz] [foo, barxbaaz] == [foo, barxbaaz] [foo, bar, baaz] == [foo, bar, baaz] [fooXXbarxxbaaz] == [fooXXbarxxbaaz] [foo, bar, baaz] == [foo, bar, baaz] libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-numericalcast.txt0000644000175000017500000002511711723544472030700 0ustar ebourgebourg ?int: 0?int=0 1?int=1 -1?int=-1 0.5?int=0 1.5?int=1 -0.5?int=0 -1.5?int=-1 0.25?int=0 -0.25?int=0 1.75?int=1 -1.75?int=-1 1.01?int=1 -1.01?int=-1 0.01?int=0 -0.01?int=0 127?int=127 128?int=128 -127?int=-127 -128?int=-128 32767?int=32767 32768?int=32768 -32767?int=-32767 -32768?int=-32768 2147483647?int=2147483647 2147483648?int=-2147483648 -2147483647?int=-2147483647 -2147483648?int=-2147483648 4294967295?int=-1 4294967296?int=0 -4294967295?int=1 -4294967296?int=0 2147483647.1?int=2147483647 2147483648.1?int=-2147483648 -2147483647.1?int=-2147483647 -2147483648.1?int=-2147483648 4294967295.1?int=-1 4294967296.1?int=0 -4294967295.1?int=1 -4294967296.1?int=0 2147483647.5?int=2147483647 2147483648.5?int=-2147483648 -2147483647.5?int=-2147483647 -2147483648.5?int=-2147483648 4294967295.5?int=-1 4294967296.5?int=0 -4294967295.5?int=1 -4294967296.5?int=0 ?double 0?double=0 1?double=1 -1?double=-1 0.5?double=0.5 1.5?double=1.5 -0.5?double=-0.5 -1.5?double=-1.5 0.25?double=0.25 -0.25?double=-0.25 1.75?double=1.75 -1.75?double=-1.75 1.01?double=1.01 -1.01?double=-1.01 0.01?double=0.01 -0.01?double=-0.01 127?double=127 128?double=128 -127?double=-127 -128?double=-128 32767?double=32767 32768?double=32768 -32767?double=-32767 -32768?double=-32768 2147483647?double=2147483647 2147483648?double=2147483648 -2147483647?double=-2147483647 -2147483648?double=-2147483648 4294967295?double=4294967295 4294967296?double=4294967296 -4294967295?double=-4294967295 -4294967296?double=-4294967296 2147483647.1?double=2147483647.1 2147483648.1?double=2147483648.1 -2147483647.1?double=-2147483647.1 -2147483648.1?double=-2147483648.1 4294967295.1?double=4294967295.1 4294967296.1?double=4294967296.1 -4294967295.1?double=-4294967295.1 -4294967296.1?double=-4294967296.1 2147483647.5?double=2147483647.5 2147483648.5?double=2147483648.5 -2147483647.5?double=-2147483647.5 -2147483648.5?double=-2147483648.5 4294967295.5?double=4294967295.5 4294967296.5?double=4294967296.5 -4294967295.5?double=-4294967295.5 -4294967296.5?double=-4294967296.5 ?long 0?long=0 1?long=1 -1?long=-1 0.5?long=0 1.5?long=1 -0.5?long=0 -1.5?long=-1 0.25?long=0 -0.25?long=0 1.75?long=1 -1.75?long=-1 1.01?long=1 -1.01?long=-1 0.01?long=0 -0.01?long=0 127?long=127 128?long=128 -127?long=-127 -128?long=-128 32767?long=32767 32768?long=32768 -32767?long=-32767 -32768?long=-32768 2147483647?long=2147483647 2147483648?long=2147483648 -2147483647?long=-2147483647 -2147483648?long=-2147483648 4294967295?long=4294967295 4294967296?long=4294967296 -4294967295?long=-4294967295 -4294967296?long=-4294967296 2147483647.1?long=2147483647 2147483648.1?long=2147483648 -2147483647.1?long=-2147483647 -2147483648.1?long=-2147483648 4294967295.1?long=4294967295 4294967296.1?long=4294967296 -4294967295.1?long=-4294967295 -4294967296.1?long=-4294967296 2147483647.5?long=2147483647 2147483648.5?long=2147483648 -2147483647.5?long=-2147483647 -2147483648.5?long=-2147483648 4294967295.5?long=4294967295 4294967296.5?long=4294967296 -4294967295.5?long=-4294967295 -4294967296.5?long=-4294967296 ?long from date 1304877615000 = 1304877615000 ?float 0?float=0 1?float=1 -1?float=-1 0.5?float=0.5 1.5?float=1.5 -0.5?float=-0.5 -1.5?float=-1.5 0.25?float=0.25 -0.25?float=-0.25 1.75?float=1.75 -1.75?float=-1.75 1.01?float=1.00999999 -1.01?float=-1.00999999 0.01?float=0.01 -0.01?float=-0.01 127?float=127 128?float=128 -127?float=-127 -128?float=-128 32767?float=32767 32768?float=32768 -32767?float=-32767 -32768?float=-32768 2147483647?float=2147483648 2147483648?float=2147483648 -2147483647?float=-2147483648 -2147483648?float=-2147483648 4294967295?float=4294967296 4294967296?float=4294967296 -4294967295?float=-4294967296 -4294967296?float=-4294967296 2147483647.1?float=2147483648 2147483648.1?float=2147483648 -2147483647.1?float=-2147483648 -2147483648.1?float=-2147483648 4294967295.1?float=4294967296 4294967296.1?float=4294967296 -4294967295.1?float=-4294967296 -4294967296.1?float=-4294967296 2147483647.5?float=2147483648 2147483648.5?float=2147483648 -2147483647.5?float=-2147483648 -2147483648.5?float=-2147483648 4294967295.5?float=4294967296 4294967296.5?float=4294967296 -4294967295.5?float=-4294967296 -4294967296.5?float=-4294967296 ?byte 0?byte=0 1?byte=1 -1?byte=-1 0.5?byte=0 1.5?byte=1 -0.5?byte=0 -1.5?byte=-1 0.25?byte=0 -0.25?byte=0 1.75?byte=1 -1.75?byte=-1 1.01?byte=1 -1.01?byte=-1 0.01?byte=0 -0.01?byte=0 127?byte=127 128?byte=-128 -127?byte=-127 -128?byte=-128 32767?byte=-1 32768?byte=0 -32767?byte=1 -32768?byte=0 2147483647?byte=-1 2147483648?byte=0 -2147483647?byte=1 -2147483648?byte=0 4294967295?byte=-1 4294967296?byte=0 -4294967295?byte=1 -4294967296?byte=0 2147483647.1?byte=-1 2147483648.1?byte=0 -2147483647.1?byte=1 -2147483648.1?byte=0 4294967295.1?byte=-1 4294967296.1?byte=0 -4294967295.1?byte=1 -4294967296.1?byte=0 2147483647.5?byte=-1 2147483648.5?byte=0 -2147483647.5?byte=1 -2147483648.5?byte=0 4294967295.5?byte=-1 4294967296.5?byte=0 -4294967295.5?byte=1 -4294967296.5?byte=0 ?short 0?short=0 1?short=1 -1?short=-1 0.5?short=0 1.5?short=1 -0.5?short=0 -1.5?short=-1 0.25?short=0 -0.25?short=0 1.75?short=1 -1.75?short=-1 1.01?short=1 -1.01?short=-1 0.01?short=0 -0.01?short=0 127?short=127 128?short=128 -127?short=-127 -128?short=-128 32767?short=32767 32768?short=-32768 -32767?short=-32767 -32768?short=-32768 2147483647?short=-1 2147483648?short=0 -2147483647?short=1 -2147483648?short=0 4294967295?short=-1 4294967296?short=0 -4294967295?short=1 -4294967296?short=0 2147483647.1?short=-1 2147483648.1?short=0 -2147483647.1?short=1 -2147483648.1?short=0 4294967295.1?short=-1 4294967296.1?short=0 -4294967295.1?short=1 -4294967296.1?short=0 2147483647.5?short=-1 2147483648.5?short=0 -2147483647.5?short=1 -2147483648.5?short=0 4294967295.5?short=-1 4294967296.5?short=0 -4294967295.5?short=1 -4294967296.5?short=0 ?floor 0?floor=0 1?floor=1 -1?floor=-1 0.5?floor=0 1.5?floor=1 -0.5?floor=-1 -1.5?floor=-2 0.25?floor=0 -0.25?floor=-1 1.75?floor=1 -1.75?floor=-2 1.01?floor=1 -1.01?floor=-2 0.01?floor=0 -0.01?floor=-1 127?floor=127 128?floor=128 -127?floor=-127 -128?floor=-128 32767?floor=32767 32768?floor=32768 -32767?floor=-32767 -32768?floor=-32768 2147483647?floor=2147483647 2147483648?floor=2147483648 -2147483647?floor=-2147483647 -2147483648?floor=-2147483648 4294967295?floor=4294967295 4294967296?floor=4294967296 -4294967295?floor=-4294967295 -4294967296?floor=-4294967296 2147483647.1?floor=2147483647 2147483648.1?floor=2147483648 -2147483647.1?floor=-2147483648 -2147483648.1?floor=-2147483649 4294967295.1?floor=4294967295 4294967296.1?floor=4294967296 -4294967295.1?floor=-4294967296 -4294967296.1?floor=-4294967297 2147483647.5?floor=2147483647 2147483648.5?floor=2147483648 -2147483647.5?floor=-2147483648 -2147483648.5?floor=-2147483649 4294967295.5?floor=4294967295 4294967296.5?floor=4294967296 -4294967295.5?floor=-4294967296 -4294967296.5?floor=-4294967297 ?ceiling 0?ceiling=0 1?ceiling=1 -1?ceiling=-1 0.5?ceiling=1 1.5?ceiling=2 -0.5?ceiling=0 -1.5?ceiling=-1 0.25?ceiling=1 -0.25?ceiling=0 1.75?ceiling=2 -1.75?ceiling=-1 1.01?ceiling=2 -1.01?ceiling=-1 0.01?ceiling=1 -0.01?ceiling=0 127?ceiling=127 128?ceiling=128 -127?ceiling=-127 -128?ceiling=-128 32767?ceiling=32767 32768?ceiling=32768 -32767?ceiling=-32767 -32768?ceiling=-32768 2147483647?ceiling=2147483647 2147483648?ceiling=2147483648 -2147483647?ceiling=-2147483647 -2147483648?ceiling=-2147483648 4294967295?ceiling=4294967295 4294967296?ceiling=4294967296 -4294967295?ceiling=-4294967295 -4294967296?ceiling=-4294967296 2147483647.1?ceiling=2147483648 2147483648.1?ceiling=2147483649 -2147483647.1?ceiling=-2147483647 -2147483648.1?ceiling=-2147483648 4294967295.1?ceiling=4294967296 4294967296.1?ceiling=4294967297 -4294967295.1?ceiling=-4294967295 -4294967296.1?ceiling=-4294967296 2147483647.5?ceiling=2147483648 2147483648.5?ceiling=2147483649 -2147483647.5?ceiling=-2147483647 -2147483648.5?ceiling=-2147483648 4294967295.5?ceiling=4294967296 4294967296.5?ceiling=4294967297 -4294967295.5?ceiling=-4294967295 -4294967296.5?ceiling=-4294967296 ?round 0?round=0 1?round=1 -1?round=-1 0.5?round=1 1.5?round=2 -0.5?round=0 -1.5?round=-1 0.25?round=0 -0.25?round=0 1.75?round=2 -1.75?round=-2 1.01?round=1 -1.01?round=-1 0.01?round=0 -0.01?round=0 127?round=127 128?round=128 -127?round=-127 -128?round=-128 32767?round=32767 32768?round=32768 -32767?round=-32767 -32768?round=-32768 2147483647?round=2147483647 2147483648?round=2147483648 -2147483647?round=-2147483647 -2147483648?round=-2147483648 4294967295?round=4294967295 4294967296?round=4294967296 -4294967295?round=-4294967295 -4294967296?round=-4294967296 2147483647.1?round=2147483647 2147483648.1?round=2147483648 -2147483647.1?round=-2147483647 -2147483648.1?round=-2147483648 4294967295.1?round=4294967295 4294967296.1?round=4294967296 -4294967295.1?round=-4294967295 -4294967296.1?round=-4294967296 2147483647.5?round=2147483648 2147483648.5?round=2147483649 -2147483647.5?round=-2147483647 -2147483648.5?round=-2147483648 4294967295.5?round=4294967296 4294967296.5?round=4294967297 -4294967295.5?round=-4294967295 -4294967296.5?round=-4294967296 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-typebuiltins.txt0000644000175000017500000000046511723544470030576 0ustar ebourgebourgStNuBoMeTaMaHaHxSeCoLiInDiNo 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-varargs.txt0000644000175000017500000000057011723544467027513 0ustar ebourgebourg 0 == 0 0 == 0 11 == 11 11 == 11 1122 == 1122 1122 == 1122 112233 == 112233 112233 == 112233 -22334411 == -22334411 -223311 == -223311 -2211 == -2211 -11 == -11 0 == 0 -11 == -11 1122 == 1122 -112233 == -112233 -11223344 == -11223344 -1122334455 == -1122334455 1122 == 1122 -1122 == -1122 string, true, 123, 1000000 == string, true, 123, 1000000 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-helloworld.html0000644000175000017500000000021711723544471030337 0ustar ebourgebourg FreeMarker: Exec Model Test

A simple test follows:

Hello, world!

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-stringbuiltins2.txt0000644000175000017500000000216411723544471031204 0ustar ebourgebourg-- 1 = 1 5 = 5 0 = 0 -- 5 = 5 1 = 1 7 = 7 -- true = true false = false true = true -- true = true false = false true = true -- true = true true = true true = true false = false true = true -- [abbcdbb] = [abbcdbb] [qwe] = [qwe] [qwe] = [qwe] [qwe] = [qwe] [qwe ] = [qwe ] [qwe ] = [qwe ] -- [abbcdbb] = [abbcdbb] [abb-dbb] = [abb-dbb] [a-=*cd-=*] = [a-=*cd-=*] -- [a][][cd][][] == [a][][cd][][] [][die][maggots][!] == [][die][maggots][!] [Die maggots!] == [Die maggots!] -- [ ] [ a] [ ab] [ abc] [ abcd] [abcde] [abcdef] [abcdefg] [abcdefgh] [-----] [----a] [---ab] [--abc] [-abcd] [abcde] [abcdef] [abcdefg] [abcdefgh] [.oO.oO.o] [.oO.oO.a] [.oO.oOab] [.oO.oabc] [.oO.abcd] [.oOabcde] [.oabcdef] [.abcdefg] [abcdefgh] [abcdefghi] [abcdefghij] [] [/] [/\] [/\_] [/\_/] [/\_/\] [/\_/\_] [/\_/\_/] -- [ ] [a ] [ab ] [abc ] [abcd ] [abcde] [abcdef] [abcdefg] [abcdefgh] [-----] [a----] [ab---] [abc--] [abcd-] [abcde] [abcdef] [abcdefg] [abcdefgh] [.oO.oO.o] [aoO.oO.o] [abO.oO.o] [abc.oO.o] [abcdoO.o] [abcdeO.o] [abcdef.o] [abcdefgo] [abcdefgh] [abcdefghi] [abcdefghij] [] [/] [/\] [/\_] [/\_/] [/\_/\] [/\_/\_] [/\_/\_/]libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-include.html0000644000175000017500000000237611723544470027616 0ustar ebourgebourg FreeMarker: Include Instruction Test

A simple test follows:

Hello, world!

Message exists!

Test normal includes:

A test of included files:

Message exists!:
Hello, world!

Can you see me? assigning from included template I'm here, mon!

Test unparsed includes:

A test of included files:

<#if .globals.message?exists>

Message exists!:
${.globals.message}

<#else>

No message :(

<#assign foo="assigning from included template", bar=" Can you see me? "> <#macro twice><#nested/>${bar}<#nested/> <#include "nestedinclude.ftl"> Kilroy Can you see me? Kilroy

Test subdir includes:

This is test-include-subdir.html

Testing including from same directory

This is test-include-subdir2.html

Testing including from relative parent

A test of included files:

Message exists!:
Hello, world!

Can you see me?

Testing including from loader root

A test of included files:

Message exists!:
Hello, world!

Can you see me?

Testing including through acquisition

This is test-include-subdir2.html

libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-bean-maps.html0000644000175000017500000000504511723544470030032 0ustar ebourgebourgproperties only, shadow (6): age : 27 class : class freemarker.testcase.TemplateTestCase$TestBean empty : false location : San Francisco luckyNumber : 7 name : Christopher properties only (6): age : 27 class : class freemarker.testcase.TemplateTestCase$TestBean empty : false location : San Francisco luckyNumber : 7 name : Chris nothing, shadow (3): age : 27 location : San Francisco name : Chris nothing (3): age : 27 location : San Francisco name : Chris all, shadow (28): age : 27 class : class freemarker.testcase.TemplateTestCase$TestBean clear : UNKNOWN clone : UNKNOWN containsKey : UNKNOWN containsValue : UNKNOWN empty : false entrySet : UNKNOWN equals : UNKNOWN get : UNKNOWN getClass : UNKNOWN getLuckyNumber : UNKNOWN getName : UNKNOWN hashCode : UNKNOWN isEmpty : UNKNOWN keySet : UNKNOWN location : San Francisco luckyNumber : 7 name : Christopher notify : UNKNOWN notifyAll : UNKNOWN put : UNKNOWN putAll : UNKNOWN remove : UNKNOWN size : UNKNOWN toString : UNKNOWN values : UNKNOWN wait : UNKNOWN all (28): age : 27 class : class freemarker.testcase.TemplateTestCase$TestBean clear : UNKNOWN clone : UNKNOWN containsKey : UNKNOWN containsValue : UNKNOWN empty : false entrySet : UNKNOWN equals : UNKNOWN get : UNKNOWN getClass : UNKNOWN getLuckyNumber : UNKNOWN getName : UNKNOWN hashCode : UNKNOWN isEmpty : UNKNOWN keySet : UNKNOWN location : San Francisco luckyNumber : 7 name : Chris notify : UNKNOWN notifyAll : UNKNOWN put : UNKNOWN putAll : UNKNOWN remove : UNKNOWN size : UNKNOWN toString : UNKNOWN values : UNKNOWN wait : UNKNOWN simple map mode (3): age : 27 location : San Francisco name : Chris String concatenation: helloworld helloworld hellohello worldworld libfreemarker-java-2.3.19.orig/src/freemarker/testcase/reference/test-new-unrestricted.txt0000644000175000017500000000001311723544470031332 0ustar ebourgebourgworks workslibfreemarker-java-2.3.19.orig/src/freemarker/testcase/test-xmlns.xml0000644000175000017500000000043011723544471025220 0ustar ebourgebourg Test Book Ch1 p1.1 p1.2 p1.3 Ch2 p2.1 p2.2 libfreemarker-java-2.3.19.orig/src/freemarker/testcase/DateUtilTest.java0000644000175000017500000002535111723544470025606 0ustar ebourgebourgpackage freemarker.testcase; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import freemarker.template.utility.DateUtil; import freemarker.template.utility.DateUtil.DateToISO8601CalendarFactory; import freemarker.template.utility.UnrecognizedTimeZoneException; import junit.framework.TestCase; public class DateUtilTest extends TestCase { private static final DateFormat DF = new SimpleDateFormat("G yyyy-MM-dd HH:mm:ss:S Z", Locale.US); static { DF.setTimeZone(DateUtil.UTC); } private DateToISO8601CalendarFactory calendarFactory = new DateUtil.TrivialDateToISO8601CalendarFactory(); public DateUtilTest(String name) { super(name); } public void testDateToUTCString() throws ParseException { assertEquals( "1998-10-30T15:30:00.512Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 1998-10-30 19:30:00:512 +0400"), true)); assertEquals( "1998-10-30T15:30:00.5Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 1998-10-30 19:30:00:500 +0400"), true)); assertEquals( "1998-10-30T15:30:00.51Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 1998-10-30 19:30:00:510 +0400"), true)); assertEquals( "1998-10-30T15:30:00.1Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 1998-10-30 19:30:00:100 +0400"), true)); assertEquals( "1998-10-30T15:30:00.01Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 1998-10-30 19:30:00:10 +0400"), true)); assertEquals( "1998-10-30T15:30:00.001Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 1998-10-30 19:30:00:1 +0400"), true)); assertEquals( "2000-02-08T06:05:04Z", dateToISO8601UTCDateTimeMSString( DF.parse("AD 2000-02-08 09:05:04:0 +0300"), true)); assertEquals( "0100-02-28T06:15:24Z", dateToISO8601UTCDateTimeString( DF.parse( "AD 0100-02-28 09:15:24:0 +0300"), true)); assertEquals( "0010-02-28T06:15:24Z", dateToISO8601UTCDateTimeString( DF.parse("AD 0010-02-28 09:15:24:0 +0300"), true)); assertEquals( "0001-02-28T06:15:24Z", dateToISO8601UTCDateTimeString( DF.parse("AD 0001-02-28 09:15:24:0 +0300"), true)); assertEquals( "0000-02-28T06:15:24Z", dateToISO8601UTCDateTimeString( DF.parse("BC 0001-02-28 09:15:24:0 +0300"), true)); assertEquals( "-1-02-28T06:15:24Z", dateToISO8601UTCDateTimeString( DF.parse("BC 2-02-28 09:15:24:0 +0300"), true)); assertEquals( "10000-02-28T06:15:24Z", dateToISO8601UTCDateTimeString( DF.parse("AD 10000-02-28 09:15:24:0 +0300"), true)); Date d = DF.parse("AD 1998-10-30 19:30:00:512 +0400"); assertEquals( "1998-10-30", dateToISO8601UTCDateString(d)); assertEquals( "15:30:00.512Z", dateToISO8601UTCTimeMSString(d, true)); assertEquals( "15:30:00.512", dateToISO8601UTCTimeMSString(d, false)); assertEquals( "1998-10-30", dateToISO8601UTCDateString( new java.sql.Date(d.getTime()))); assertEquals( "15:30:00.512Z", dateToISO8601UTCTimeMSString( new java.sql.Time(d.getTime()), true)); } public void testLocalTime() throws ParseException { Date dsum = DF.parse("AD 2010-05-09 20:00:00:0 UTC"); Date dwin = DF.parse("AD 2010-01-01 20:00:00:0 UTC"); TimeZone tzRome = TimeZone.getTimeZone("Europe/Rome"); if (tzRome.getOffset(0) == 0) { throw new RuntimeException( "Can't get time zone for Europe/Rome!"); } assertEquals( "2010-05-09T22:00:00+02:00", dateToISO8601DateTimeString(dsum, tzRome)); assertEquals( "2010-01-01T21:00:00+01:00", dateToISO8601DateTimeString(dwin, tzRome)); assertEquals( "2010-05-09", dateToISO8601DateString(dsum, tzRome)); assertEquals( "2010-01-01", dateToISO8601DateString(dwin, tzRome)); assertEquals( "22:00:00+02:00", dateToISO8601TimeString(dsum, tzRome)); assertEquals( "21:00:00+01:00", dateToISO8601TimeString(dwin, tzRome)); TimeZone tzNY = TimeZone.getTimeZone("America/New_York"); if (tzNY.getOffset(0) == 0) { throw new RuntimeException( "Can't get time zone for America/New_York!"); } assertEquals( "2010-05-09T16:00:00-04:00", dateToISO8601DateTimeString(dsum, tzNY)); assertEquals( "2010-01-01T15:00:00-05:00", dateToISO8601DateTimeString(dwin, tzNY)); assertEquals( "2010-05-09", dateToISO8601DateString(dsum, tzNY)); assertEquals( "2010-01-01", dateToISO8601DateString(dwin, tzNY)); assertEquals( "16:00:00-04:00", dateToISO8601TimeString(dsum, tzNY)); assertEquals( "15:00:00-05:00", dateToISO8601TimeString(dwin, tzNY)); TimeZone tzFixed = TimeZone.getTimeZone("GMT+02:30"); assertEquals( "2010-05-09T22:30:00+02:30", dateToISO8601DateTimeString(dsum, tzFixed)); assertEquals( "2010-01-01T22:30:00+02:30", dateToISO8601DateTimeString(dwin, tzFixed)); } public void testGetTimeZone() throws Exception { assertTrue(DateUtil.getTimeZone("GMT") != DateUtil.UTC); assertTrue(DateUtil.getTimeZone("UT1") != DateUtil.UTC); assertEquals(DateUtil.getTimeZone("UTC"), DateUtil.UTC); assertEquals(DateUtil.getTimeZone("Europe/Rome"), TimeZone.getTimeZone("Europe/Rome")); assertEquals(DateUtil.getTimeZone("Iceland"), // GMT and no DST TimeZone.getTimeZone("Iceland")); try { DateUtil.getTimeZone("Europe/NoSuch"); fail(); } catch (UnrecognizedTimeZoneException e) { // good } } public void testTimeOnlyDate() throws UnrecognizedTimeZoneException { Date t = new Date(0L); SimpleDateFormat tf = new SimpleDateFormat("HH:mm:ss"); tf.setTimeZone(DateUtil.UTC); assertEquals("00:00:00", tf.format(t)); assertEquals("00:00:00", dateToISO8601UTCTimeString(t, false)); TimeZone gmt1 = DateUtil.getTimeZone("GMT+01"); tf.setTimeZone(gmt1); assertEquals("01:00:00", tf.format(t)); assertEquals("01:00:00+01:00", dateToISO8601TimeString(t, gmt1)); } public void testAccuracy() throws ParseException { Date d = DF.parse("AD 2000-02-08 09:05:04:250 UTC"); assertEquals("2000-02-08T09:05:04Z", dateToISO8601UTCDateTimeString(d, true)); assertEquals("2000-02-08T09:05:04.25Z", dateToISO8601String(d, true, true, true, DateUtil.ACCURACY_MILLISECONDS, null)); assertEquals("2000-02-08T09:05:04Z", dateToISO8601String(d, true, true, true, DateUtil.ACCURACY_SECONDS, null)); assertEquals("2000-02-08T09:05Z", dateToISO8601String(d, true, true, true, DateUtil.ACCURACY_MINUTES, null)); assertEquals("2000-02-08T09Z", dateToISO8601String(d, true, true, true, DateUtil.ACCURACY_HOURS, null)); } private String dateToISO8601DateTimeString( Date date, TimeZone tz) { return dateToISO8601String(date, true, true, true, DateUtil.ACCURACY_SECONDS, tz); } private String dateToISO8601UTCDateTimeString( Date date, boolean offsetPart) { return dateToISO8601String(date, true, true, offsetPart, DateUtil.ACCURACY_SECONDS, DateUtil.UTC); } private String dateToISO8601UTCDateTimeMSString( Date date, boolean offsetPart) { return dateToISO8601String(date, true, true, offsetPart, DateUtil.ACCURACY_MILLISECONDS, DateUtil.UTC); } private String dateToISO8601DateString(Date date, TimeZone tz) { return dateToISO8601String(date, true, false, false, DateUtil.ACCURACY_SECONDS, tz); } private String dateToISO8601UTCDateString(Date date) { return dateToISO8601String(date, true, false, false, DateUtil.ACCURACY_SECONDS, DateUtil.UTC); } private String dateToISO8601TimeString( Date date, TimeZone tz) { return dateToISO8601String(date, false, true, true, DateUtil.ACCURACY_SECONDS, tz); } private String dateToISO8601UTCTimeString( Date date, boolean offsetPart) { return dateToISO8601String(date, false, true, offsetPart, DateUtil.ACCURACY_SECONDS, DateUtil.UTC); } private String dateToISO8601UTCTimeMSString( Date date, boolean offsetPart) { return dateToISO8601String(date, false, true, offsetPart, DateUtil.ACCURACY_MILLISECONDS, DateUtil.UTC); } private String dateToISO8601String( Date date, boolean datePart, boolean timePart, boolean offsetPart, int accuracy, TimeZone timeZone) { return DateUtil.dateToISO8601String( date, datePart, timePart, offsetPart, accuracy, timeZone, calendarFactory); } } libfreemarker-java-2.3.19.orig/src/freemarker/testcase/testcases.xml0000644000175000017500000001737111723544470025113 0ustar ebourgebourg ]> libfreemarker-java-2.3.19.orig/src/freemarker/testcase/package.html0000644000175000017500000000163411723544470024647 0ustar ebourgebourg

Test cases for various aspects of the FreeMarker implementation. These use the JUnit testing framework to carry out and report on tests.

To run the tests:

  • Get a copy of JUnit from the JUnit web site
  • Modify testcase.properties to point to the FreeMarker testcase directory on your local machine
  • Run one of the TestRunners in JUnit, such as junit.swingui.TestRunner
  • Point the TestRunner at freemarker.testcase.FreeMarkerTestSuite
  • Look for green...

Any errors will result in the text of the failed test case(s) appearing in your current working directory. From there it should be possible to diagnose the cause of the failure.

libfreemarker-java-2.3.19.orig/src/freemarker/log/0000755000175000017500000000000012164627123021325 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/log/Log4JLoggerFactory.java0000644000175000017500000001076311723544471025612 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; import org.apache.log4j.Level; /** * @version $Id: Log4JLoggerFactory.java,v 1.8 2005/05/04 12:02:43 ddekany Exp $ * @author Attila Szegedi */ class Log4JLoggerFactory implements LoggerFactory { public Logger getLogger(String category) { return new Log4JLogger(org.apache.log4j.Logger.getLogger(category)); } private static class Log4JLogger extends Logger { private final org.apache.log4j.Logger logger; Log4JLogger(org.apache.log4j.Logger logger) { this.logger = logger; } public void debug(String message) { logger.debug(message); } public void debug(String message, Throwable t) { logger.debug(message, t); } public void error(String message) { logger.error(message); } public void error(String message, Throwable t) { logger.error(message, t); } public void info(String message) { logger.info(message); } public void info(String message, Throwable t) { logger.info(message, t); } public void warn(String message) { logger.warn(message); } public void warn(String message, Throwable t) { logger.warn(message, t); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isEnabledFor(Level.WARN); } public boolean isErrorEnabled() { return logger.isEnabledFor(Level.ERROR); } public boolean isFatalEnabled() { return logger.isEnabledFor(Level.FATAL); } } } libfreemarker-java-2.3.19.orig/src/freemarker/log/AvalonLoggerFactory.java0000644000175000017500000001075411723544470026112 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; import org.apache.log.Hierarchy; /** * @version $Id: AvalonLoggerFactory.java,v 1.7 2003/01/27 20:36:43 szegedia Exp $ * @author Attila Szegedi */ class AvalonLoggerFactory implements LoggerFactory { public Logger getLogger(String category) { return new AvalonLogger(Hierarchy.getDefaultHierarchy().getLoggerFor(category)); } private static class AvalonLogger extends Logger { private final org.apache.log.Logger logger; AvalonLogger(org.apache.log.Logger logger) { this.logger = logger; } public void debug(String message) { logger.debug(message); } public void debug(String message, Throwable t) { logger.debug(message, t); } public void error(String message) { logger.error(message); } public void error(String message, Throwable t) { logger.error(message, t); } public void info(String message) { logger.info(message); } public void info(String message, Throwable t) { logger.info(message, t); } public void warn(String message) { logger.warn(message); } public void warn(String message, Throwable t) { logger.warn(message, t); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isFatalEnabled() { return logger.isFatalErrorEnabled(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/log/SLF4JLoggerFactory.java0000644000175000017500000001415011723544471025507 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; import org.slf4j.spi.LocationAwareLogger; public class SLF4JLoggerFactory implements LoggerFactory { public Logger getLogger(String category) { org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger(category); if (slf4jLogger instanceof LocationAwareLogger) { return new LocationAwareSLF4JLogger((LocationAwareLogger) slf4jLogger); } else { return new LocationUnawareSLF4JLogger(slf4jLogger); } } /** * Logger where the log entry issuer (class, method) will be correctly * shown to be the caller of LocationAwareSLF4JLogger methods. */ private static final class LocationAwareSLF4JLogger extends Logger { private static final String ADAPTER_FQCN = LocationAwareSLF4JLogger.class.getName(); private final LocationAwareLogger logger; LocationAwareSLF4JLogger(LocationAwareLogger logger) { this.logger = logger; } public void debug(String message) { debug(message, null); } public void debug(String message, Throwable t) { logger.log(null, ADAPTER_FQCN, LocationAwareLogger.DEBUG_INT, message, null, t); } public void info(String message) { info(message, null); } public void info(String message, Throwable t) { logger.log(null, ADAPTER_FQCN, LocationAwareLogger.INFO_INT, message, null, t); } public void warn(String message) { warn(message, null); } public void warn(String message, Throwable t) { logger.log(null, ADAPTER_FQCN, LocationAwareLogger.WARN_INT, message, null, t); } public void error(String message) { error(message, null); } public void error(String message, Throwable t) { logger.log(null, ADAPTER_FQCN, LocationAwareLogger.ERROR_INT, message, null, t); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isFatalEnabled() { return logger.isErrorEnabled(); } } /** * Logger where the log entry issuer (class, method) will be incorrectly * shown to be a method of this class. */ private static class LocationUnawareSLF4JLogger extends Logger { private final org.slf4j.Logger logger; LocationUnawareSLF4JLogger(org.slf4j.Logger logger) { this.logger = logger; } public void debug(String message) { logger.debug(message); } public void debug(String message, Throwable t) { logger.debug(message, t); } public void info(String message) { logger.info(message); } public void info(String message, Throwable t) { logger.info(message, t); } public void warn(String message) { logger.warn(message); } public void warn(String message, Throwable t) { logger.warn(message, t); } public void error(String message) { logger.error(message); } public void error(String message, Throwable t) { logger.error(message, t); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isFatalEnabled() { return logger.isErrorEnabled(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/log/NullLoggerFactory.java0000644000175000017500000000757311723544470025611 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; /** * @version $Id: NullLoggerFactory.java,v 1.9 2003/01/27 20:36:45 szegedia Exp $ * @author Attila Szegedi */ class NullLoggerFactory implements LoggerFactory { NullLoggerFactory() { } public Logger getLogger(String category) { return INSTANCE; } private static final Logger INSTANCE = new Logger() { public void debug(String message) { } public void debug(String message, Throwable t) { } public void error(String message) { } public void error(String message, Throwable t) { } public void info(String message) { } public void info(String message, Throwable t) { } public void warn(String message) { } public void warn(String message, Throwable t) { } public boolean isDebugEnabled() { return false; } public boolean isInfoEnabled() { return false; } public boolean isWarnEnabled() { return false; } public boolean isErrorEnabled() { return false; } public boolean isFatalEnabled() { return false; } }; } libfreemarker-java-2.3.19.orig/src/freemarker/log/LoggerFactory.java0000644000175000017500000000536211723544467024756 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; /** * @version $Id: LoggerFactory.java,v 1.5 2003/01/12 23:40:17 revusky Exp $ * @author Attila Szegedi */ interface LoggerFactory { public Logger getLogger(String category); } libfreemarker-java-2.3.19.orig/src/freemarker/log/Logger.java0000644000175000017500000002732011723544470023416 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; import java.util.HashMap; import java.util.Map; import freemarker.template.utility.ClassUtil; /** * The FreeMarker logging facility. This is a polymorphic implementation * that will use whatever logging package it can find on the system: * Apache Log4J, Apache Avalon LogKit, java.util.logging (in this * order). If it fails to find any of the above, logging will be suppressed * and a short notice will be printed to System.err. * *

You can use the {@link #selectLoggerLibrary(int)} static method to force * use of a specific logger package, or to turn off logging. * *

SLF4J or Apache Commons Logging are supported (since FreeMarker 2.3.17) * and recommended, but are never selected automatically (until FreeMarker 2.4) * due to backward compatibility constraints; you have to select them * explicitly with {@link #selectLoggerLibrary(int)}. * * @author Attila Szegedi */ public abstract class Logger { /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should automatically lookup and use any available logger library. */ public static final int LIBRARY_AUTO = -1; /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should use no logger package (i.e. turn off logging). */ public static final int LIBRARY_NONE = 0; /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should use the java.util.logging logger package. */ public static final int LIBRARY_JAVA = 1; /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should use the Apache Jakarta Avalon LogKit logger package. */ public static final int LIBRARY_AVALON = 2; /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should use the Apache Jakarta Log4J logger package. */ public static final int LIBRARY_LOG4J = 3; /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should use the Apache commons-logging logger adapter package. */ public static final int LIBRARY_COMMONS = 4; /** * Constant used with {@link #selectLoggerLibrary(int)} that indicates the * engine should use the SLF4J logger adapter package. */ public static final int LIBRARY_SLF4J = 5; /** * Order matters! Starts with the lowest priority. */ private static final String[] LIBINIT = { "freemarker.log.Logger", "Null", "java.util.logging.Logger", "JDK14", "org.apache.log.Logger", "Avalon", "org.apache.log4j.Logger", "Log4J", /* In 2.3.x this two is skipped by LIBRARY_AUTO: */ "org.apache.commons.logging.Log", "CommonsLogging", "org.slf4j.Logger", "SLF4J", }; private static int logLibrary; private static LoggerFactory factory; private static String categoryPrefix = ""; private static final Map loggers = new HashMap(); /** * Selects the logger library to use. * If you want to change the default setting, do it early in application * initialization phase, before calling any other FreeMarker API since once * various parts of the FreeMarker library bind to the logging subsystem, * the change in this value will have no effect on them. * @param library one of LIBRARY_XXX constants. By default, * {@link #LIBRARY_AUTO} is used. * @throws ClassNotFoundException if an explicit logging library is asked for * (that is, neither NONE, nor AUTO), and it is not found in the classpath. */ public static void selectLoggerLibrary(int library) throws ClassNotFoundException { synchronized (Logger.class) { if(library < -1 || (library*2) >= LIBINIT.length) { throw new IllegalArgumentException(); } logLibrary = library; factory = createFactory(); } } /** * Sets a category prefix. This prefix is prepended to any logger category * name. This makes it possible to have different FreeMarker logger categories * on a per-application basis (better said, per-classloader basis). By default * the category prefix is the empty string. If you set a non-empty category * prefix, be sure to include the trailing separator dot (i.e. "MyApp.") * If you want to change the default setting, do it early in application * initialization phase, before calling any other FreeMarker API since once * various parts of the FreeMarker library bind to the logging subsystem, * the change in this value will have no effect on them. */ public static void setCategoryPrefix(String prefix) { synchronized (Logger.class) { if(prefix == null) { throw new IllegalArgumentException(); } categoryPrefix = prefix; } } /** * Logs a debugging message. */ public abstract void debug(String message); /** * Logs a debugging message with accompanying throwable. */ public abstract void debug(String message, Throwable t); /** * Logs an informational message. */ public abstract void info(String message); /** * Logs an informational message with accompanying throwable. */ public abstract void info(String message, Throwable t); /** * Logs a warning message. */ public abstract void warn(String message); /** * Logs a warning message with accompanying throwable. */ public abstract void warn(String message, Throwable t); /** * Logs an error message. */ public abstract void error(String message); /** * Logs an error message with accompanying throwable. */ public abstract void error(String message, Throwable t); /** * Returns true if this logger will log debug messages. */ public abstract boolean isDebugEnabled(); /** * Returns true if this logger will log informational messages. */ public abstract boolean isInfoEnabled(); /** * Returns true if this logger will log warning messages. */ public abstract boolean isWarnEnabled(); /** * Returns true if this logger will log error messages. */ public abstract boolean isErrorEnabled(); /** * Returns true if this logger will log fatal error messages. */ public abstract boolean isFatalEnabled(); /** * Returns a logger for the specified category. * @param category a dot separated hierarchical category name. If a category * prefix is in effect, it is prepended to the category name. */ public static Logger getLogger(String category) { if (factory == null) { synchronized (Logger.class) { if (factory == null) { try { selectLoggerLibrary(LIBRARY_AUTO); } catch(ClassNotFoundException e) { // This can't happen, really throw new RuntimeException(e.getMessage()); } } } } category = categoryPrefix + category; synchronized(loggers) { Logger logger = (Logger)loggers.get(category); if(logger == null) { logger = factory.getLogger(category); loggers.put(category, logger); } return logger; } } private static LoggerFactory createFactory() throws ClassNotFoundException { if(logLibrary == LIBRARY_AUTO) { for(int i = LIBINIT.length / 2 - 1; i > 0; --i) { // For backward-compatibility we skip these in 2.3.x: if (i == LIBRARY_SLF4J || i == LIBRARY_COMMONS) continue; try { return createFactory(i); } catch(ClassNotFoundException e) { ;//Intentionally ignored } } System.err.println("*** WARNING: FreeMarker logging suppressed."); return new NullLoggerFactory(); } else { return createFactory(logLibrary); } } private static LoggerFactory createFactory(int library) throws ClassNotFoundException { String loggerClassName = LIBINIT[library * 2]; String factoryType = LIBINIT[library * 2 + 1]; try { ClassUtil.forName(loggerClassName); return (LoggerFactory)Class.forName("freemarker.log." + factoryType + "LoggerFactory").newInstance(); } catch(IllegalAccessException e) { // This can't happen, really throw new IllegalAccessError(e.getMessage()); } catch(InstantiationException e) { // This can't happen, really throw new InstantiationError(e.getMessage()); } } } libfreemarker-java-2.3.19.orig/src/freemarker/log/CommonsLoggingLoggerFactory.java0000644000175000017500000001010311723544470027600 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; public class CommonsLoggingLoggerFactory implements LoggerFactory { public Logger getLogger(String category) { return new CommonsLoggingLogger( org.apache.commons.logging.LogFactory.getLog(category)); } static private class CommonsLoggingLogger extends Logger { private final org.apache.commons.logging.Log logger; CommonsLoggingLogger(org.apache.commons.logging.Log logger) { this.logger = logger; } public void debug(String message) { logger.debug(message); } public void debug(String message, Throwable t) { logger.debug(message, t); } public void info(String message) { logger.info(message); } public void info(String message, Throwable t) { logger.info(message, t); } public void warn(String message) { logger.warn(message); } public void warn(String message, Throwable t) { logger.warn(message, t); } public void error(String message) { logger.error(message); } public void error(String message, Throwable t) { logger.error(message, t); } public boolean isDebugEnabled() { return logger.isDebugEnabled(); } public boolean isInfoEnabled() { return logger.isInfoEnabled(); } public boolean isWarnEnabled() { return logger.isWarnEnabled(); } public boolean isErrorEnabled() { return logger.isErrorEnabled(); } public boolean isFatalEnabled() { return logger.isFatalEnabled(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/log/JDK14LoggerFactory.java0000644000175000017500000001114211723544472025441 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.log; import java.util.logging.Level; /** * @version $Id: JDK14LoggerFactory.java,v 1.8 2003/01/27 20:36:44 szegedia Exp $ * @author Attila Szegedi */ class JDK14LoggerFactory implements LoggerFactory { public Logger getLogger(String category) { return new JDK14Logger(java.util.logging.Logger.getLogger(category)); } private static class JDK14Logger extends Logger { private final java.util.logging.Logger logger; JDK14Logger(java.util.logging.Logger logger) { this.logger = logger; } public void debug(String message) { logger.log(Level.FINE, message); } public void debug(String message, Throwable t) { logger.log(Level.FINE, message, t); } public void error(String message) { logger.log(Level.SEVERE, message); } public void error(String message, Throwable t) { logger.log(Level.SEVERE, message, t); } public void info(String message) { logger.log(Level.INFO, message); } public void info(String message, Throwable t) { logger.log(Level.INFO, message, t); } public void warn(String message) { logger.log(Level.WARNING, message); } public void warn(String message, Throwable t) { logger.log(Level.WARNING, message, t); } public boolean isDebugEnabled() { return logger.isLoggable(Level.FINE); } public boolean isInfoEnabled() { return logger.isLoggable(Level.INFO); } public boolean isWarnEnabled() { return logger.isLoggable(Level.WARNING); } public boolean isErrorEnabled() { return logger.isLoggable(Level.SEVERE); } public boolean isFatalEnabled() { return logger.isLoggable(Level.SEVERE); } } } libfreemarker-java-2.3.19.orig/src/freemarker/log/package.html0000644000175000017500000000013211723544470023605 0ustar ebourgebourg

Provides the FreeMarker logging facility. libfreemarker-java-2.3.19.orig/src/freemarker/version.properties0000644000175000017500000000427511723544471024363 0ustar ebourgebourg# $Id: version.properties,v 1.21.2.13 2007/04/20 12:03:56 ddekany Exp $ # Version info for the builds. # Version string. # # Examples: # Version number Means # 2.2.5 5th bugfix/improved release of the 2.2 series. # 2.3pre13 13th preview of incoming version "2.3" # 2.3pre13mod Unreleased modified version of 2.3pre13. The nightly # builds after releasing 2.3pre13 but before the releasing # of the next version should be marked as this. # 2.3rc1 1st release candidate of incoming version "2.3" # 2.3 The 1st release of the 2.3 series. # 3.0 The 1st release of the 3.0 series. # # Notes on version numbering policy: # - "pre" and "rc" (lowercase!) means "preview" and "release # candidate" respectively. It is must be followed with a # number (as "1" for the first release candidate). # - "mod" after the version number indicates, that it's an # unreleased modified version of the released version. # After releases, the "mod" should be added, as the nighly builds # are such releases. # - The 2nd version number must be present, and maybe 0, # as in "3.0". # - The 3rd version number is never 0. E.g. the version # number string for the first release of the 2.2 series # is "2.2", and NOT "2.2.0". # - When only the 3rd version number increases # (2.2 -> 2.2.1, 2.2.1 -> 2.2.2 etc.), 100% backward compatiblity # with the previous version MUST be kept. # This means that freemarker.jar can be replaced in an application # without risk (as far as the application doesn't depend on the # presence of a FreeMarker bug). # Note that backward compatibility restrictions do not apply for # preview releases. version=2.3.19 # Version string for Manifest.mf: dot separated numbers. # # Examples: # version -> versionForMf # 2.2.5 -> 2.2.5 # 2.3pre13 -> 2.2.98.13 # 2.3pre13mod -> 2.2.98.13.97 # 2.3rc1 -> 2.2.99.1 # 2.3 -> 2.3 # 2.3mod -> 2.3.0.97 # 3.0pre2 -> 2.98.2 # # 97 denotes "mod" (a generic nightly build), 98 denotes "pre", 99 denotes "rc". # In general, for the preview Y or rc Y of version 2.X, the versionForMf is # 2.X-1.(99|98).Y. Note the X-1. versionForMf=2.3.19 libfreemarker-java-2.3.19.orig/src/freemarker/debug/0000755000175000017500000000000012164627123021632 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/0000755000175000017500000000000012164627123022573 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/RmiDebuggerImpl.java0000644000175000017500000000323611723544467026471 0ustar ebourgebourgpackage freemarker.debug.impl; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.Collection; import java.util.List; import freemarker.debug.Breakpoint; import freemarker.debug.Debugger; import freemarker.debug.DebuggerListener; /** * @author Attila Szegedi * @version $Id: RmiDebuggerImpl.java,v 1.2.2.1 2006/11/27 07:54:49 szegedia Exp $ */ class RmiDebuggerImpl extends UnicastRemoteObject implements Debugger { private static final long serialVersionUID = 1L; private final RmiDebuggerService service; protected RmiDebuggerImpl(RmiDebuggerService service) throws RemoteException { this.service = service; } public void addBreakpoint(Breakpoint breakpoint) { service.addBreakpoint(breakpoint); } public Object addDebuggerListener(DebuggerListener listener) { return service.addDebuggerListener(listener); } public List getBreakpoints() { return service.getBreakpointsSpi(); } public List getBreakpoints(String templateName) { return service.getBreakpointsSpi(templateName); } public Collection getSuspendedEnvironments() { return service.getSuspendedEnvironments(); } public void removeBreakpoint(Breakpoint breakpoint) { service.removeBreakpoint(breakpoint); } public void removeDebuggerListener(Object id) { service.removeDebuggerListener(id); } public void removeBreakpoints() { service.removeBreakpoints(); } public void removeBreakpoints(String templateName) { service.removeBreakpoints(templateName); } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/RmiDebuggerListenerImpl.java0000644000175000017500000000267111723544471030174 0ustar ebourgebourgpackage freemarker.debug.impl; import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.rmi.server.Unreferenced; import freemarker.debug.DebuggerClient; import freemarker.debug.DebuggerListener; import freemarker.debug.EnvironmentSuspendedEvent; import freemarker.log.Logger; /** * Used by the {@link DebuggerClient} to create local * @author Attila Szegedi * @version $Id: RmiDebuggerListenerImpl.java,v 1.1.2.1 2006/11/27 07:54:49 szegedia Exp $ */ public class RmiDebuggerListenerImpl extends UnicastRemoteObject implements DebuggerListener, Unreferenced { private static final Logger logger = Logger.getLogger( "freemarker.debug.client"); private static final long serialVersionUID = 1L; private final DebuggerListener listener; public void unreferenced() { try { UnicastRemoteObject.unexportObject(this, false); } catch (NoSuchObjectException e) { logger.warn("Failed to unexport RMI debugger listener", e); } } public RmiDebuggerListenerImpl(DebuggerListener listener) throws RemoteException { this.listener = listener; } public void environmentSuspended(EnvironmentSuspendedEvent e) throws RemoteException { listener.environmentSuspended(e); } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/RmiDebuggedEnvironmentImpl.java0000644000175000017500000002333711723544471030677 0ustar ebourgebourgpackage freemarker.debug.impl; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import freemarker.cache.CacheStorage; import freemarker.cache.SoftCacheStorage; import freemarker.core.Configurable; import freemarker.core.Environment; import freemarker.debug.DebugModel; import freemarker.debug.DebuggedEnvironment; import freemarker.ext.util.IdentityHashMap; import freemarker.template.Configuration; import freemarker.template.SimpleCollection; import freemarker.template.SimpleScalar; import freemarker.template.Template; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: RmiDebuggedEnvironmentImpl.java,v 1.3.2.2 2006/11/27 07:55:17 szegedia Exp $ */ class RmiDebuggedEnvironmentImpl extends RmiDebugModelImpl implements DebuggedEnvironment { private static final long serialVersionUID = 1L; private static final CacheStorage storage = new SoftCacheStorage(new IdentityHashMap()); private static final Object idLock = new Object(); private static long nextId = 1; private boolean stopped = false; private final long id; private RmiDebuggedEnvironmentImpl(Environment env) throws RemoteException { super(new DebugEnvironmentModel(env), DebugModel.TYPE_ENVIRONMENT); synchronized(idLock) { id = nextId++; } } static synchronized Object getCachedWrapperFor(Object key) throws RemoteException { Object value = storage.get(key); if(value == null) { if(key instanceof TemplateModel) { int extraTypes; if(key instanceof DebugConfigurationModel) { extraTypes = DebugModel.TYPE_CONFIGURATION; } else if(key instanceof DebugTemplateModel) { extraTypes = DebugModel.TYPE_TEMPLATE; } else { extraTypes = 0; } value = new RmiDebugModelImpl((TemplateModel)key, extraTypes); } else if(key instanceof Environment) { value = new RmiDebuggedEnvironmentImpl((Environment)key); } else if(key instanceof Template) { value = new DebugTemplateModel((Template)key); } else if(key instanceof Configuration) { value = new DebugConfigurationModel((Configuration)key); } } return value; } public void resume() { synchronized(this) { notify(); } } public void stop() { stopped = true; resume(); } public long getId() { return id; } boolean isStopped() { return stopped; } private abstract static class DebugMapModel implements TemplateHashModelEx { public int size() { return keySet().size(); } public TemplateCollectionModel keys() { return new SimpleCollection(keySet()); } public TemplateCollectionModel values() throws TemplateModelException { Collection keys = keySet(); List list = new ArrayList(keys.size()); for(Iterator it = keys.iterator(); it.hasNext();) { list.add(get((String)it.next())); } return new SimpleCollection(list); } public boolean isEmpty() { return size() == 0; } abstract Collection keySet(); static List composeList(Collection c1, Collection c2) { List list = new ArrayList(c1); list.addAll(c2); Collections.sort(list); return list; } } private static class DebugConfigurableModel extends DebugMapModel { static final List KEYS = Arrays.asList(new String[] { Configurable.ARITHMETIC_ENGINE_KEY, Configurable.BOOLEAN_FORMAT_KEY, Configurable.CLASSIC_COMPATIBLE_KEY, Configurable.LOCALE_KEY, Configurable.NUMBER_FORMAT_KEY, Configurable.OBJECT_WRAPPER_KEY, Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY }); final Configurable configurable; DebugConfigurableModel(Configurable configurable) { this.configurable = configurable; } Collection keySet() { return KEYS; } public TemplateModel get(String key) throws TemplateModelException { String s = configurable.getSetting(key); return s == null ? null : new SimpleScalar(s); } } private static class DebugConfigurationModel extends DebugConfigurableModel { private static final List KEYS = composeList(DebugConfigurableModel.KEYS, Collections.singleton("sharedVariables")); private TemplateModel sharedVariables = new DebugMapModel() { Collection keySet() { return ((Configuration)configurable).getSharedVariableNames(); } public TemplateModel get(String key) { return ((Configuration)configurable).getSharedVariable(key); } }; DebugConfigurationModel(Configuration config) { super(config); } Collection keySet() { return KEYS; } public TemplateModel get(String key) throws TemplateModelException { if("sharedVariables".equals(key)) { return sharedVariables; } else { return super.get(key); } } } private static class DebugTemplateModel extends DebugConfigurableModel { private static final List KEYS = composeList(DebugConfigurableModel.KEYS, Arrays.asList(new String[] { "configuration", "name", })); private final SimpleScalar name; DebugTemplateModel(Template template) { super(template); this.name = new SimpleScalar(template.getName()); } Collection keySet() { return KEYS; } public TemplateModel get(String key) throws TemplateModelException { if("configuration".equals(key)) { try { return (TemplateModel)getCachedWrapperFor(((Template)configurable).getConfiguration()); } catch (RemoteException e) { throw new TemplateModelException(e); } } if("name".equals(key)) { return name; } return super.get(key); } } private static class DebugEnvironmentModel extends DebugConfigurableModel { private static final List KEYS = composeList(DebugConfigurableModel.KEYS, Arrays.asList(new String[] { "currentNamespace", "dataModel", "globalNamespace", "knownVariables", "mainNamespace", "template", })); private TemplateModel knownVariables = new DebugMapModel() { Collection keySet() { try { return ((Environment)configurable).getKnownVariableNames(); } catch (TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public TemplateModel get(String key) throws TemplateModelException { return ((Environment)configurable).getVariable(key); } }; DebugEnvironmentModel(Environment env) { super(env); } Collection keySet() { return KEYS; } public TemplateModel get(String key) throws TemplateModelException { if("currentNamespace".equals(key)) { return ((Environment)configurable).getCurrentNamespace(); } if("dataModel".equals(key)) { return ((Environment)configurable).getDataModel(); } if("globalNamespace".equals(key)) { return ((Environment)configurable).getGlobalNamespace(); } if("knownVariables".equals(key)) { return knownVariables; } if("mainNamespace".equals(key)) { return ((Environment)configurable).getMainNamespace(); } if("template".equals(key)) { try { return (TemplateModel) getCachedWrapperFor(((Environment)configurable).getTemplate()); } catch (RemoteException e) { throw new TemplateModelException(e); } } return super.get(key); } } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/DebuggerServer.java0000644000175000017500000001354211723544470026361 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug.impl; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.ServerSocket; import java.net.Socket; import java.security.MessageDigest; import java.security.SecureRandom; import java.util.Arrays; import java.util.Random; import freemarker.debug.Debugger; import freemarker.log.Logger; import freemarker.template.utility.SecurityUtilities; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: DebuggerServer.java,v 1.3 2004/09/09 15:34:38 szegedia Exp $ */ class DebuggerServer { private static final Logger logger = Logger.getLogger("freemarker.debug.server"); // TODO: Eventually replace with Yarrow private static final Random R = new SecureRandom(); private final byte[] password; private final int port; private final Serializable debuggerStub; public DebuggerServer(Serializable debuggerStub) { port = SecurityUtilities.getSystemProperty("freemarker.debug.port", Debugger.DEFAULT_PORT).intValue(); try { password = SecurityUtilities.getSystemProperty("freemarker.debug.password", "").getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { throw new UndeclaredThrowableException(e); } this.debuggerStub = debuggerStub; } public void start() { new Thread(new Runnable() { public void run() { startInternal(); } }, "FreeMarker Debugger Server Acceptor").start(); } private void startInternal() { try { ServerSocket ss = new ServerSocket(port); for(;;) { Socket s = ss.accept(); new Thread(new DebuggerAuthProtocol(s)).start(); } } catch(IOException e) { logger.error("Debugger server shut down.", e); } } private class DebuggerAuthProtocol implements Runnable { private final Socket s; DebuggerAuthProtocol(Socket s) { this.s = s; } public void run() { try { ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); ObjectInputStream in = new ObjectInputStream(s.getInputStream()); byte[] challenge = new byte[512]; R.nextBytes(challenge); out.writeInt(220); // protocol version out.writeObject(challenge); MessageDigest md = MessageDigest.getInstance("SHA"); md.update(password); md.update(challenge); byte[] response = (byte[])in.readObject(); if(Arrays.equals(response, md.digest())) { out.writeObject(debuggerStub); } else { out.writeObject(null); } } catch(Exception e) { logger.warn("Connection to " + s.getInetAddress().getHostAddress() + " abruply broke", e); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/DebuggerService.java0000644000175000017500000001131211723544471026505 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug.impl; import java.rmi.RemoteException; import java.util.Collections; import java.util.List; import freemarker.core.Environment; import freemarker.template.Template; import freemarker.template.utility.SecurityUtilities; /** * This class provides debugging hooks for the core FreeMarker engine. It is * not usable for anyone outside the FreeMarker core classes. It is public only * as an implementation detail. * @author Attila Szegedi * @version $Id: DebuggerService.java,v 1.2 2003/05/30 16:51:53 szegedia Exp $ */ public abstract class DebuggerService { private static final DebuggerService instance = createInstance(); private static DebuggerService createInstance() { // Creates the appropriate service class. If the debugging is turned // off, this is a fast no-op service, otherwise it is the real-thing // RMI service. return SecurityUtilities.getSystemProperty("freemarker.debug.password") == null ? (DebuggerService)new NoOpDebuggerService() : (DebuggerService)new RmiDebuggerService(); } public static List getBreakpoints(String templateName) { return instance.getBreakpointsSpi(templateName); } abstract List getBreakpointsSpi(String templateName); public static void registerTemplate(Template template) { instance.registerTemplateSpi(template); } abstract void registerTemplateSpi(Template template); public static boolean suspendEnvironment(Environment env, int line) throws RemoteException { return instance.suspendEnvironmentSpi(env, line); } abstract boolean suspendEnvironmentSpi(Environment env, int line) throws RemoteException; private static class NoOpDebuggerService extends DebuggerService { List getBreakpointsSpi(String templateName) { return Collections.EMPTY_LIST; } boolean suspendEnvironmentSpi(Environment env, int line) { throw new UnsupportedOperationException(); } void registerTemplateSpi(Template template) { } } }libfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/RmiDebugModelImpl.java0000644000175000017500000001230411723544470026742 0ustar ebourgebourgpackage freemarker.debug.impl; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.Date; import java.util.List; import freemarker.debug.DebugModel; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.TemplateTransformModel; /** * @author Attila Szegedi * @version $Id: RmiDebugModelImpl.java,v 1.2.2.1 2006/11/27 07:54:49 szegedia Exp $ */ class RmiDebugModelImpl extends UnicastRemoteObject implements DebugModel { private static final long serialVersionUID = 1L; private final TemplateModel model; private final int type; RmiDebugModelImpl(TemplateModel model, int extraTypes) throws RemoteException { super(); this.model = model; type = calculateType(model) + extraTypes; } private static DebugModel getDebugModel(TemplateModel tm) throws RemoteException { return (DebugModel)RmiDebuggedEnvironmentImpl.getCachedWrapperFor(tm); } public String getAsString() throws TemplateModelException { return ((TemplateScalarModel)model).getAsString(); } public Number getAsNumber() throws TemplateModelException { return ((TemplateNumberModel)model).getAsNumber(); } public Date getAsDate() throws TemplateModelException { return ((TemplateDateModel)model).getAsDate(); } public int getDateType() { return ((TemplateDateModel)model).getDateType(); } public boolean getAsBoolean() throws TemplateModelException { return ((TemplateBooleanModel)model).getAsBoolean(); } public int size() throws TemplateModelException { if(model instanceof TemplateSequenceModel) { return ((TemplateSequenceModel)model).size(); } return ((TemplateHashModelEx)model).size(); } public DebugModel get(int index) throws TemplateModelException, RemoteException { return getDebugModel(((TemplateSequenceModel)model).get(index)); } public DebugModel[] get(int fromIndex, int toIndex) throws TemplateModelException, RemoteException { DebugModel[] dm = new DebugModel[toIndex - fromIndex]; TemplateSequenceModel s = (TemplateSequenceModel)model; for (int i = fromIndex; i < toIndex; i++) { dm[i - fromIndex] = getDebugModel(s.get(i)); } return dm; } public DebugModel[] getCollection() throws TemplateModelException, RemoteException { List list = new ArrayList(); TemplateModelIterator i = ((TemplateCollectionModel)model).iterator(); while(i.hasNext()) { list.add(getDebugModel(i.next())); } return (DebugModel[])list.toArray(new DebugModel[list.size()]); } public DebugModel get(String key) throws TemplateModelException, RemoteException { return getDebugModel(((TemplateHashModel)model).get(key)); } public DebugModel[] get(String[] keys) throws TemplateModelException, RemoteException { DebugModel[] dm = new DebugModel[keys.length]; TemplateHashModel h = (TemplateHashModel)model; for (int i = 0; i < keys.length; i++) { dm[i] = getDebugModel(h.get(keys[i])); } return dm; } public String[] keys() throws TemplateModelException { TemplateHashModelEx h = (TemplateHashModelEx)model; List list = new ArrayList(); TemplateModelIterator i = h.keys().iterator(); while(i.hasNext()) { list.add(((TemplateScalarModel)i.next()).getAsString()); } return (String[])list.toArray(new String[list.size()]); } public int getModelTypes() { return type; } private static int calculateType(TemplateModel model) { int type = 0; if(model instanceof TemplateScalarModel) type += TYPE_SCALAR; if(model instanceof TemplateNumberModel) type += TYPE_NUMBER; if(model instanceof TemplateDateModel) type += TYPE_DATE; if(model instanceof TemplateBooleanModel) type += TYPE_BOOLEAN; if(model instanceof TemplateSequenceModel) type += TYPE_SEQUENCE; if(model instanceof TemplateCollectionModel) type += TYPE_COLLECTION; if(model instanceof TemplateHashModelEx) type += TYPE_HASH_EX; else if(model instanceof TemplateHashModel) type += TYPE_HASH; if(model instanceof TemplateMethodModelEx) type += TYPE_METHOD_EX; else if(model instanceof TemplateMethodModel) type += TYPE_METHOD; if(model instanceof TemplateTransformModel) type += TYPE_TRANSFORM; return type; } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/impl/RmiDebuggerService.java0000644000175000017500000003551411723544471027167 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug.impl; import java.io.Serializable; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.rmi.RemoteException; import java.rmi.server.RemoteObject; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import freemarker.core.DebugBreak; import freemarker.core.Environment; import freemarker.core.TemplateElement; import freemarker.debug.Breakpoint; import freemarker.debug.DebuggerListener; import freemarker.debug.EnvironmentSuspendedEvent; import freemarker.template.Template; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id */ class RmiDebuggerService extends DebuggerService { private final Map templateDebugInfos = new HashMap(); private final HashSet suspendedEnvironments = new HashSet(); private final Map listeners = new HashMap(); private final ReferenceQueue refQueue = new ReferenceQueue(); RmiDebuggerService() { try { new DebuggerServer((Serializable)RemoteObject.toStub(new RmiDebuggerImpl(this))).start(); } catch(RemoteException e) { e.printStackTrace(); throw new UndeclaredThrowableException(e); } } List getBreakpointsSpi(String templateName) { synchronized(templateDebugInfos) { TemplateDebugInfo tdi = findTemplateDebugInfo(templateName); return tdi == null ? Collections.EMPTY_LIST : tdi.breakpoints; } } List getBreakpointsSpi() { List sumlist = new ArrayList(); synchronized(templateDebugInfos) { for (Iterator iter = templateDebugInfos.values().iterator(); iter.hasNext();) { sumlist.addAll(((TemplateDebugInfo) iter.next()).breakpoints); } } Collections.sort(sumlist); return sumlist; } boolean suspendEnvironmentSpi(Environment env, int line) throws RemoteException { RmiDebuggedEnvironmentImpl denv = (RmiDebuggedEnvironmentImpl) RmiDebuggedEnvironmentImpl.getCachedWrapperFor(env); synchronized(suspendedEnvironments) { suspendedEnvironments.add(denv); } try { EnvironmentSuspendedEvent breakpointEvent = new EnvironmentSuspendedEvent(this, line, denv); synchronized(listeners) { for (Iterator iter = listeners.values().iterator(); iter.hasNext();) { DebuggerListener listener = (DebuggerListener) iter.next(); listener.environmentSuspended(breakpointEvent); } } synchronized(denv) { try { denv.wait(); } catch(InterruptedException e) { ;// Intentionally ignored } } return denv.isStopped(); } finally { synchronized(suspendedEnvironments) { suspendedEnvironments.remove(denv); } } } void registerTemplateSpi(Template template) { String templateName = template.getName(); synchronized(templateDebugInfos) { TemplateDebugInfo tdi = createTemplateDebugInfo(templateName); tdi.templates.add(new TemplateReference(templateName, template, refQueue)); // Inject already defined breakpoints into the template for (Iterator iter = tdi.breakpoints.iterator(); iter.hasNext();) { Breakpoint breakpoint = (Breakpoint) iter.next(); insertDebugBreak(template, breakpoint); } } } Collection getSuspendedEnvironments() { return (Collection)suspendedEnvironments.clone(); } Object addDebuggerListener(DebuggerListener listener) { Object id; synchronized(listeners) { id = new Long(System.currentTimeMillis()); listeners.put(id, listener); } return id; } void removeDebuggerListener(Object id) { synchronized(listeners) { listeners.remove(id); } } void addBreakpoint(Breakpoint breakpoint) { String templateName = breakpoint.getTemplateName(); synchronized(templateDebugInfos) { TemplateDebugInfo tdi = createTemplateDebugInfo(templateName); List breakpoints = tdi.breakpoints; int pos = Collections.binarySearch(breakpoints, breakpoint); if(pos < 0) { // Add to the list of breakpoints breakpoints.add(-pos - 1, breakpoint); // Inject the breakpoint into all templates with this name for (Iterator iter = tdi.templates.iterator(); iter.hasNext();) { TemplateReference ref = (TemplateReference) iter.next(); Template t = ref.getTemplate(); if(t == null) { iter.remove(); } else { insertDebugBreak(t, breakpoint); } } } } } private static void insertDebugBreak(Template t, Breakpoint breakpoint) { TemplateElement te = findTemplateElement(t.getRootTreeNode(), breakpoint.getLine()); if(te == null) { return; } TemplateElement parent = (TemplateElement)te.getParent(); DebugBreak db = new DebugBreak(te); // TODO: Ensure there always is a parent by making sure // that the root element in the template is always a MixedContent // Also make sure it doesn't conflict with anyone's code. parent.setChildAt(parent.getIndex(te), db); } private static TemplateElement findTemplateElement(TemplateElement te, int line) { if(te.getBeginLine() > line || te.getEndLine() < line) { return null; } // Find the narrowest match for(Enumeration children = te.children(); children.hasMoreElements();) { TemplateElement child = (TemplateElement)children.nextElement(); TemplateElement childmatch = findTemplateElement(child, line); if(childmatch != null) { return childmatch; } } // If no child provides narrower match, return this return te; } private TemplateDebugInfo findTemplateDebugInfo(String templateName) { processRefQueue(); return (TemplateDebugInfo)templateDebugInfos.get(templateName); } private TemplateDebugInfo createTemplateDebugInfo(String templateName) { TemplateDebugInfo tdi = findTemplateDebugInfo(templateName); if(tdi == null) { tdi = new TemplateDebugInfo(); templateDebugInfos.put(templateName, tdi); } return tdi; } void removeBreakpoint(Breakpoint breakpoint) { String templateName = breakpoint.getTemplateName(); synchronized(templateDebugInfos) { TemplateDebugInfo tdi = findTemplateDebugInfo(templateName); if(tdi != null) { List breakpoints = tdi.breakpoints; int pos = Collections.binarySearch(breakpoints, breakpoint); if(pos >= 0) { breakpoints.remove(pos); for (Iterator iter = tdi.templates.iterator(); iter.hasNext();) { TemplateReference ref = (TemplateReference) iter.next(); Template t = ref.getTemplate(); if(t == null) { iter.remove(); } else { removeDebugBreak(t, breakpoint); } } } if(tdi.isEmpty()) { templateDebugInfos.remove(templateName); } } } } private void removeDebugBreak(Template t, Breakpoint breakpoint) { TemplateElement te = findTemplateElement(t.getRootTreeNode(), breakpoint.getLine()); if(te == null) { return; } DebugBreak db = null; while(te != null) { if(te instanceof DebugBreak) { db = (DebugBreak)te; break; } te = (TemplateElement)te.getParent(); } if(db == null) { return; } TemplateElement parent = (TemplateElement)db.getParent(); parent.setChildAt(parent.getIndex(db), (TemplateElement)db.getChildAt(0)); } void removeBreakpoints(String templateName) { synchronized(templateDebugInfos) { TemplateDebugInfo tdi = findTemplateDebugInfo(templateName); if(tdi != null) { removeBreakpoints(tdi); if(tdi.isEmpty()) { templateDebugInfos.remove(templateName); } } } } void removeBreakpoints() { synchronized(templateDebugInfos) { for (Iterator iter = templateDebugInfos.values().iterator(); iter.hasNext();) { TemplateDebugInfo tdi = (TemplateDebugInfo) iter.next(); removeBreakpoints(tdi); if(tdi.isEmpty()) { iter.remove(); } } } } private void removeBreakpoints(TemplateDebugInfo tdi) { tdi.breakpoints.clear(); for (Iterator iter = tdi.templates.iterator(); iter.hasNext();) { TemplateReference ref = (TemplateReference) iter.next(); Template t = ref.getTemplate(); if(t == null) { iter.remove(); } else { removeDebugBreaks(t.getRootTreeNode()); } } } private void removeDebugBreaks(TemplateElement te) { int count = te.getChildCount(); for(int i = 0; i < count; ++i) { TemplateElement child = (TemplateElement)te.getChildAt(i); while(child instanceof DebugBreak) { TemplateElement dbchild = (TemplateElement)child.getChildAt(0); te.setChildAt(i, dbchild); child = dbchild; } removeDebugBreaks(child); } } private static final class TemplateDebugInfo { final List templates = new ArrayList(); final List breakpoints = new ArrayList(); boolean isEmpty() { return templates.isEmpty() && breakpoints.isEmpty(); } } private static final class TemplateReference extends WeakReference { final String templateName; TemplateReference(String templateName, Template template, ReferenceQueue queue) { super(template, queue); this.templateName = templateName; } Template getTemplate() { return (Template)get(); } } private void processRefQueue() { for(;;) { TemplateReference ref = (TemplateReference)refQueue.poll(); if(ref == null) { break; } TemplateDebugInfo tdi = findTemplateDebugInfo(ref.templateName); if(tdi != null) { tdi.templates.remove(ref); if(tdi.isEmpty()) { templateDebugInfos.remove(ref.templateName); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/DebugModel.java0000644000175000017500000001316311723544471024514 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.Date; import freemarker.template.TemplateModelException; /** * Represents the debugger-side mirror of a TemplateModel object, a Template * object, or a Configuration object. The Environment objects are also represented * by instances of this model, although not directly but through a separate * subinterface {@link DebuggedEnvironment}. The interface is a union of * almost all of FreeMarker template models with identical method signatures. * For purposes of optimizing network traffic there are bulk retrieval methods * for sequences and hashes, as well as a {@link #getModelTypes()} method that * returns a bit mask of various TYPE_xxx constants flagging which * template models are implemented by the mirrored object. * * @author Attila Szegedi * @version $Id: DebugModel.java,v 1.2 2003/06/08 00:58:16 herbyderby Exp $ */ public interface DebugModel extends Remote { public static final int TYPE_SCALAR = 1; public static final int TYPE_NUMBER = 2; public static final int TYPE_DATE = 4; public static final int TYPE_BOOLEAN = 8; public static final int TYPE_SEQUENCE = 16; public static final int TYPE_COLLECTION = 32; public static final int TYPE_HASH = 64; public static final int TYPE_HASH_EX = 128; public static final int TYPE_METHOD = 256; public static final int TYPE_METHOD_EX = 512; public static final int TYPE_TRANSFORM = 1024; public static final int TYPE_ENVIRONMENT = 2048; public static final int TYPE_TEMPLATE = 4096; public static final int TYPE_CONFIGURATION = 8192; public String getAsString() throws TemplateModelException, RemoteException; public Number getAsNumber() throws TemplateModelException, RemoteException; public boolean getAsBoolean() throws TemplateModelException, RemoteException; public Date getAsDate() throws TemplateModelException, RemoteException; public int getDateType() throws TemplateModelException, RemoteException; public int size() throws TemplateModelException, RemoteException; public DebugModel get(int index) throws TemplateModelException, RemoteException; public DebugModel[] get(int fromIndex, int toIndex) throws TemplateModelException, RemoteException; public DebugModel get(String key) throws TemplateModelException, RemoteException; public DebugModel[] get(String[] keys) throws TemplateModelException, RemoteException; public DebugModel[] getCollection() throws TemplateModelException, RemoteException; public String[] keys() throws TemplateModelException, RemoteException; public int getModelTypes() throws RemoteException; } libfreemarker-java-2.3.19.orig/src/freemarker/debug/Debugger.java0000644000175000017500000001212611723544472024230 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.Collection; import java.util.List; /** * The main debugger interface. Allows management of breakpoints as well as * installation of listeners for debug events. * @author Attila Szegedi * @version $Id: Debugger.java,v 1.1 2003/05/02 15:55:48 szegedia Exp $ */ public interface Debugger extends Remote { public static final int DEFAULT_PORT = 7011; /** * Adds a breakpoint * @param breakpoint the breakpoint to add * @throws RemoteException */ public void addBreakpoint(Breakpoint breakpoint) throws RemoteException; /** * Removes a single breakpoint * @param breakpoint the breakpoint to remove * @throws RemoteException */ public void removeBreakpoint(Breakpoint breakpoint) throws RemoteException; /** * Removes all breakpoints for a specific template * @param templateName * @throws RemoteException */ public void removeBreakpoints(String templateName) throws RemoteException; /** * Removes all breakpoints * @throws RemoteException */ public void removeBreakpoints() throws RemoteException; /** * Retrieves a list of all {@link Breakpoint} objects. * @throws RemoteException */ public List getBreakpoints() throws RemoteException; /** * Retrieves a list of all {@link Breakpoint} objects for the specified * template. * @throws RemoteException */ public List getBreakpoints(String templateName) throws RemoteException; /** * Retrieves a collection of all {@link DebuggedEnvironment} objects that * are currently suspended. * @throws RemoteException */ public Collection getSuspendedEnvironments() throws RemoteException; /** * Adds a listener for debugger events. * @return an identification token that should be passed to * {@link #removeDebuggerListener(Object)} to remove this listener. * @throws RemoteException */ public Object addDebuggerListener(DebuggerListener listener) throws RemoteException; /** * Removes a previously added debugger listener. * @param id the identification token for the listener that was returned * from a prior call to {@link #addDebuggerListener(DebuggerListener)}. * @throws RemoteException */ public void removeDebuggerListener(Object id) throws RemoteException; } libfreemarker-java-2.3.19.orig/src/freemarker/debug/DebuggerListener.java0000644000175000017500000000116411723544467025742 0ustar ebourgebourgpackage freemarker.debug; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.EventListener; /** * An interface for components that wish to receive debugging events. * @author Attila Szegedi * @version $Id: DebuggerListener.java,v 1.1 2003/05/02 15:55:48 szegedia Exp $ */ public interface DebuggerListener extends Remote, EventListener { /** * Called whenever an environment gets suspended (ie hits a breakpoint). * @param e the event object * @throws RemoteException */ public void environmentSuspended(EnvironmentSuspendedEvent e) throws RemoteException; } libfreemarker-java-2.3.19.orig/src/freemarker/debug/Breakpoint.java0000644000175000017500000001035611723544470024603 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug; import java.io.Serializable; /** * Represents a breakpoint location consisting of a template name and a line number. * @author Attila Szegedi * @version $Id: Breakpoint.java,v 1.1.2.1 2006/11/27 07:54:19 szegedia Exp $ */ public class Breakpoint implements Serializable, Comparable { private static final long serialVersionUID = 1L; private final String templateName; private final int line; /** * Creates a new breakpoint. * @param templateName the name of the template * @param line the line number in the template where to put the breakpoint */ public Breakpoint(String templateName, int line) { this.templateName = templateName; this.line = line; } /** * Returns the line number of the breakpoint */ public int getLine() { return line; } /** * Returns the template name of the breakpoint */ public String getTemplateName() { return templateName; } public int hashCode() { return templateName.hashCode() + 31 * line; } public boolean equals(Object o) { if(o instanceof Breakpoint) { Breakpoint b = (Breakpoint)o; return b.templateName.equals(templateName) && b.line == line; } return false; } public int compareTo(Object o) { Breakpoint b = (Breakpoint)o; int r = templateName.compareTo(b.templateName); return r == 0 ? line - b.line : r; } /** * Returns the template name and the line number separated with a colon */ public String getLocationString() { return templateName + ":" + line; } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/EnvironmentSuspendedEvent.java0000644000175000017500000000177211723544470027670 0ustar ebourgebourgpackage freemarker.debug; import java.util.EventObject; /** * Event describing a suspension of an environment (ie because it hit a * breakpoint). * @author Attila Szegedi * @version $Id: EnvironmentSuspendedEvent.java,v 1.1.2.1 2006/11/27 07:54:19 szegedia Exp $ */ public class EnvironmentSuspendedEvent extends EventObject { private static final long serialVersionUID = 1L; private final int line; private final DebuggedEnvironment env; public EnvironmentSuspendedEvent(Object source, int line, DebuggedEnvironment env) { super(source); this.line = line; this.env = env; } /** * The line number in the template where the execution of the environment * was suspended. * @return int the line number */ public int getLine() { return line; } /** * The environment that was suspended * @return DebuggedEnvironment */ public DebuggedEnvironment getEnvironment() { return env; } } libfreemarker-java-2.3.19.orig/src/freemarker/debug/DebuggedEnvironment.java0000644000175000017500000000314611723544471026440 0ustar ebourgebourgpackage freemarker.debug; import java.rmi.RemoteException; /** * Represents the debugger-side mirror of a debugged * {@link freemarker.core.Environment} object in the remote VM. This interface * extends {@link DebugModel}, and the properties of the Environment are exposed * as hash keys on it. Specifically, the following keys are supported: * "currentNamespace", "dataModel", "globalNamespace", "knownVariables", * "mainNamespace", and "template". *

The debug model for the template supports keys "configuration" and "name". *

The debug model for the configuration supports key "sharedVariables". *

Additionally, all of the debug models for environment, template, and * configuration also support all the setting keys of * {@link freemarker.core.Configurable} objects. * @author Attila Szegedi * @version $Id: DebuggedEnvironment.java,v 1.1 2003/05/02 15:55:48 szegedia Exp $ */ public interface DebuggedEnvironment extends DebugModel { /** * Resumes the processing of the environment in the remote VM after it was * stopped on a breakpoint. * @throws RemoteException */ public void resume() throws RemoteException; /** * Stops the processing of the environment after it was stopped on * a breakpoint. Causes a {@link freemarker.core.StopException} to be * thrown in the processing thread in the remote VM. * @throws RemoteException */ public void stop() throws RemoteException; /** * Returns a unique identifier for this environment * @throws RemoteException */ public long getId() throws RemoteException; } libfreemarker-java-2.3.19.orig/src/freemarker/debug/DebuggerClient.java0000644000175000017500000001667211723544471025400 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.debug; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.InetAddress; import java.net.Socket; import java.rmi.RemoteException; import java.rmi.server.RemoteObject; import java.security.MessageDigest; import java.util.Collection; import java.util.List; import freemarker.debug.impl.RmiDebuggerListenerImpl; import freemarker.template.utility.UndeclaredThrowableException; /** * A utility class that allows you to connect to the FreeMarker debugger service * running on a specific host and port. * @author Attila Szegedi * @version $Id: DebuggerClient.java,v 1.3.2.1 2006/11/27 07:54:19 szegedia Exp $ */ public class DebuggerClient { private DebuggerClient() { } /** * Connects to the FreeMarker debugger service running on a specific host * and port. The Java VM to which the connection is made must have defined * the system property freemarker.debug.password in order to enable * the debugger service. Additionally, the freemarker.debug.port * system property can be set to specify the port where the debugger service * is listening. When not specified, it defaults to * {@link Debugger#DEFAULT_PORT}. * @param host the host address of the machine where the debugger service is * running. * @param port the port of the debugger service * @param password the password required to connect to the debugger service * @return Debugger a debugger object. null is returned in case incorrect * password was supplied. * @throws IOException if an exception occurs. */ public static Debugger getDebugger(InetAddress host, int port, String password) throws IOException { try { Socket s = new Socket(host, port); try { ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); ObjectInputStream in = new ObjectInputStream(s.getInputStream()); int protocolVersion = in.readInt(); if(protocolVersion > 220) { throw new IOException( "Incompatible protocol version " + protocolVersion + ". At most 220 was expected."); } byte[] challenge = (byte[])in.readObject(); MessageDigest md = MessageDigest.getInstance("SHA"); md.update(password.getBytes("UTF-8")); md.update(challenge); out.writeObject(md.digest()); return new LocalDebuggerProxy((Debugger)in.readObject()); //return (Debugger)in.readObject(); } finally { s.close(); } } catch(IOException e) { throw e; } catch(Exception e) { throw new UndeclaredThrowableException(e); } } private static class LocalDebuggerProxy implements Debugger { private final Debugger remoteDebugger; LocalDebuggerProxy(Debugger remoteDebugger) { this.remoteDebugger = remoteDebugger; } public void addBreakpoint(Breakpoint breakpoint) throws RemoteException { remoteDebugger.addBreakpoint(breakpoint); } public Object addDebuggerListener(DebuggerListener listener) throws RemoteException { if(listener instanceof RemoteObject) { return remoteDebugger.addDebuggerListener(listener); } else { RmiDebuggerListenerImpl remotableListener = new RmiDebuggerListenerImpl(listener); return remoteDebugger.addDebuggerListener(remotableListener); } } public List getBreakpoints() throws RemoteException { return remoteDebugger.getBreakpoints(); } public List getBreakpoints(String templateName) throws RemoteException { return remoteDebugger.getBreakpoints(templateName); } public Collection getSuspendedEnvironments() throws RemoteException { return remoteDebugger.getSuspendedEnvironments(); } public void removeBreakpoint(Breakpoint breakpoint) throws RemoteException { remoteDebugger.removeBreakpoint(breakpoint); } public void removeBreakpoints(String templateName) throws RemoteException { remoteDebugger.removeBreakpoints(templateName); } public void removeBreakpoints() throws RemoteException { remoteDebugger.removeBreakpoints(); } public void removeDebuggerListener(Object id) throws RemoteException { remoteDebugger.removeDebuggerListener(id); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/0000755000175000017500000000000011723544471021350 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/util/0000755000175000017500000000000012164627123022321 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/util/WrapperTemplateModel.java0000644000175000017500000000613011723544471027265 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.util; import freemarker.template.TemplateModel; /** * A generic interface for template models that wrap some underlying * object, and wish to provide access to the wrapped object. * @deprecated use {@link freemarker.template.AdapterTemplateModel} instead. * @version $Id: WrapperTemplateModel.java,v 1.9 2005/06/12 19:03:06 szegedia Exp $ * @author Attila Szegedi */ public interface WrapperTemplateModel extends TemplateModel { /** * Retrieves the object wrapped by this model. */ public Object getWrappedObject(); } libfreemarker-java-2.3.19.orig/src/freemarker/ext/util/IdentityHashMap.java0000644000175000017500000007107711723544472026240 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.util; import java.util.AbstractCollection; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /** * A variant of {@link java.util.HashMap} that uses * {@link System#identityHashCode(Object)} for hashing, and reference comparison * instead of {@link Object#equals(Object)}. Note that this applies only to keys, * and not to values, i.e. {@link #containsValue(Object)} still uses {@link Object#equals(Object)}. * @author Attila Szegedi */ public class IdentityHashMap extends AbstractMap implements Map, Cloneable, java.io.Serializable { public static final long serialVersionUID = 362498820763181265L; /** * The hash table data. */ private transient Entry table[]; /** * The total number of mappings in the hash table. */ private transient int count; /** * The table is rehashed when its size exceeds this threshold. (The * value of this field is (int)(capacity * loadFactor).) * * @serial */ private int threshold; /** * The load factor for the hashtable. * * @serial */ private float loadFactor; /** * The number of times this IdentityHashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the IdentityHashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the IdentityHashMap fail-fast. (See ConcurrentModificationException). */ private transient int modCount = 0; /** * Constructs a new, empty map with the specified initial * capacity and the specified load factor. * * @param initialCapacity the initial capacity of the IdentityHashMap. * @param loadFactor the load factor of the IdentityHashMap * @throws IllegalArgumentException if the initial capacity is less * than zero, or if the load factor is nonpositive. */ public IdentityHashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException( "Illegal Initial Capacity: " + initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException( "Illegal Load factor: " + loadFactor); if (initialCapacity == 0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry[initialCapacity]; threshold = (int) (initialCapacity * loadFactor); } /** * Constructs a new, empty map with the specified initial capacity * and default load factor, which is 0.75. * * @param initialCapacity the initial capacity of the IdentityHashMap. * @throws IllegalArgumentException if the initial capacity is less * than zero. */ public IdentityHashMap(int initialCapacity) { this(initialCapacity, 0.75f); } /** * Constructs a new, empty map with a default capacity and load * factor, which is 0.75. */ public IdentityHashMap() { this(11, 0.75f); } /** * Constructs a new map with the same mappings as the given map. The * map is created with a capacity of twice the number of mappings in * the given map or 11 (whichever is greater), and a default load factor, * which is 0.75. * * @param t the map whose mappings are to be placed in this map. */ public IdentityHashMap(Map t) { this(Math.max(2 * t.size(), 11), 0.75f); putAll(t); } /** * Returns the number of key-value mappings in this map. * * @return the number of key-value mappings in this map. */ public int size() { return count; } /** * Returns true if this map contains no key-value mappings. * * @return true if this map contains no key-value mappings. */ public boolean isEmpty() { return count == 0; } /** * Returns true if this map maps one or more keys to the * specified value. * * @param value value whose presence in this map is to be tested. * @return true if this map maps one or more keys to the * specified value. */ public boolean containsValue(Object value) { Entry tab[] = table; if (value == null) { for (int i = tab.length; i-- > 0;) for (Entry e = tab[i]; e != null; e = e.next) if (e.value == null) return true; } else { for (int i = tab.length; i-- > 0;) for (Entry e = tab[i]; e != null; e = e.next) if (value.equals(e.value)) return true; } return false; } /** * Returns true if this map contains a mapping for the specified * key. * * @return true if this map contains a mapping for the specified * key. * @param key key whose presence in this Map is to be tested. */ public boolean containsKey(Object key) { Entry tab[] = table; if (key != null) { int hash = System.identityHashCode(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index]; e != null; e = e.next) if (e.hash == hash && key == e.key) return true; } else { for (Entry e = tab[0]; e != null; e = e.next) if (e.key == null) return true; } return false; } /** * Returns the value to which this map maps the specified key. Returns * null if the map contains no mapping for this key. A return * value of null does not necessarily indicate that the * map contains no mapping for the key; it's also possible that the map * explicitly maps the key to null. The containsKey * operation may be used to distinguish these two cases. * * @return the value to which this map maps the specified key. * @param key key whose associated value is to be returned. */ public Object get(Object key) { Entry tab[] = table; if (key != null) { int hash = System.identityHashCode(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index]; e != null; e = e.next) if ((e.hash == hash) && key == e.key) return e.value; } else { for (Entry e = tab[0]; e != null; e = e.next) if (e.key == null) return e.value; } return null; } /** * Rehashes the contents of this map into a new IdentityHashMap instance * with a larger capacity. This method is called automatically when the * number of keys in this map exceeds its capacity and load factor. */ private void rehash() { int oldCapacity = table.length; Entry oldMap[] = table; int newCapacity = oldCapacity * 2 + 1; Entry newMap[] = new Entry[newCapacity]; modCount++; threshold = (int) (newCapacity * loadFactor); table = newMap; for (int i = oldCapacity; i-- > 0;) { for (Entry old = oldMap[i]; old != null;) { Entry e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } } /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for this key, the old * value is replaced. * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @return previous value associated with specified key, or null * if there was no mapping for key. A null return can * also indicate that the IdentityHashMap previously associated * null with the specified key. */ public Object put(Object key, Object value) { // Makes sure the key is not already in the IdentityHashMap. Entry tab[] = table; int hash = 0; int index = 0; if (key != null) { hash = System.identityHashCode(key); index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index]; e != null; e = e.next) { if ((e.hash == hash) && key == e.key) { Object old = e.value; e.value = value; return old; } } } else { for (Entry e = tab[0]; e != null; e = e.next) { if (e.key == null) { Object old = e.value; e.value = value; return old; } } } modCount++; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. Entry e = new Entry(hash, key, value, tab[index]); tab[index] = e; count++; return null; } /** * Removes the mapping for this key from this map if present. * * @param key key whose mapping is to be removed from the map. * @return previous value associated with specified key, or null * if there was no mapping for key. A null return can * also indicate that the map previously associated null * with the specified key. */ public Object remove(Object key) { Entry tab[] = table; if (key != null) { int hash = System.identityHashCode(key); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) { if ((e.hash == hash) && key == e.key) { modCount++; if (prev != null) prev.next = e.next; else tab[index] = e.next; count--; Object oldValue = e.value; e.value = null; return oldValue; } } } else { for (Entry e = tab[0], prev = null; e != null; prev = e, e = e.next) { if (e.key == null) { modCount++; if (prev != null) prev.next = e.next; else tab[0] = e.next; count--; Object oldValue = e.value; e.value = null; return oldValue; } } } return null; } /** * Copies all of the mappings from the specified map to this one. * * These mappings replace any mappings that this map had for any of the * keys currently in the specified Map. * * @param t Mappings to be stored in this map. */ public void putAll(Map t) { Iterator i = t.entrySet().iterator(); while (i.hasNext()) { Map.Entry e = (Map.Entry) i.next(); put(e.getKey(), e.getValue()); } } /** * Removes all mappings from this map. */ public void clear() { Entry tab[] = table; modCount++; for (int index = tab.length; --index >= 0;) tab[index] = null; count = 0; } /** * Returns a shallow copy of this IdentityHashMap instance: the keys and * values themselves are not cloned. * * @return a shallow copy of this map. */ public Object clone() { try { IdentityHashMap t = (IdentityHashMap) super.clone(); t.table = new Entry[table.length]; for (int i = table.length; i-- > 0;) { t.table[i] = (table[i] != null) ? (Entry) table[i].clone() : null; } t.keySet = null; t.entrySet = null; t.values = null; t.modCount = 0; return t; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } // Views private transient Set keySet = null; private transient Set entrySet = null; private transient Collection values = null; /** * Returns a set view of the keys contained in this map. The set is * backed by the map, so changes to the map are reflected in the set, and * vice versa. The set supports element removal, which removes the * corresponding mapping from this map, via the Iterator.remove, * Set.remove, removeAll, retainAll, and * clear operations. It does not support the add or * addAll operations. * * @return a set view of the keys contained in this map. */ public Set keySet() { if (keySet == null) { keySet = new AbstractSet() { public Iterator iterator() { return getHashIterator(KEYS); } public int size() { return count; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { int oldSize = count; IdentityHashMap.this.remove(o); return count != oldSize; } public void clear() { IdentityHashMap.this.clear(); } }; } return keySet; } /** * Returns a collection view of the values contained in this map. The * collection is backed by the map, so changes to the map are reflected in * the collection, and vice versa. The collection supports element * removal, which removes the corresponding mapping from this map, via the * Iterator.remove, Collection.remove, * removeAll, retainAll, and clear operations. * It does not support the add or addAll operations. * * @return a collection view of the values contained in this map. */ public Collection values() { if (values == null) { values = new AbstractCollection() { public Iterator iterator() { return getHashIterator(VALUES); } public int size() { return count; } public boolean contains(Object o) { return containsValue(o); } public void clear() { IdentityHashMap.this.clear(); } }; } return values; } /** * Returns a collection view of the mappings contained in this map. Each * element in the returned collection is a Map.Entry. The * collection is backed by the map, so changes to the map are reflected in * the collection, and vice versa. The collection supports element * removal, which removes the corresponding mapping from the map, via the * Iterator.remove, Collection.remove, * removeAll, retainAll, and clear operations. * It does not support the add or addAll operations. * * @return a collection view of the mappings contained in this map. * @see java.util.Map.Entry */ public Set entrySet() { if (entrySet == null) { entrySet = new AbstractSet() { public Iterator iterator() { return getHashIterator(ENTRIES); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry entry = (Map.Entry) o; Object key = entry.getKey(); Entry tab[] = table; int hash = (key == null ? 0 : System.identityHashCode(key)); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index]; e != null; e = e.next) if (e.hash == hash && e.equals(entry)) return true; return false; } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry entry = (Map.Entry) o; Object key = entry.getKey(); Entry tab[] = table; int hash = (key == null ? 0 : System.identityHashCode(key)); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e.hash == hash && e.equals(entry)) { modCount++; if (prev != null) prev.next = e.next; else tab[index] = e.next; count--; e.value = null; return true; } } return false; } public int size() { return count; } public void clear() { IdentityHashMap.this.clear(); } }; } return entrySet; } private Iterator getHashIterator(int type) { if (count == 0) { return emptyHashIterator; } else { return new HashIterator(type); } } /** * IdentityHashMap collision list entry. */ private static class Entry implements Map.Entry { int hash; Object key; Object value; Entry next; Entry(int hash, Object key, Object value, Entry next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } protected Object clone() { return new Entry( hash, key, value, (next == null ? null : (Entry) next.clone())); } // Map.Entry Ops public Object getKey() { return key; } public Object getValue() { return value; } public Object setValue(Object value) { Object oldValue = this.value; this.value = value; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; return (key == e.getKey()) && (value == null ? e.getValue() == null : value.equals(e.getValue())); } public int hashCode() { return hash ^ (value == null ? 0 : value.hashCode()); } public String toString() { return key + "=" + value; } } // Types of Iterators private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2; private static EmptyHashIterator emptyHashIterator = new EmptyHashIterator(); private static class EmptyHashIterator implements Iterator { EmptyHashIterator() { } public boolean hasNext() { return false; } public Object next() { throw new NoSuchElementException(); } public void remove() { throw new IllegalStateException(); } } private class HashIterator implements Iterator { Entry[] table = IdentityHashMap.this.table; int index = table.length; Entry entry = null; Entry lastReturned = null; int type; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ private int expectedModCount = modCount; HashIterator(int type) { this.type = type; } public boolean hasNext() { Entry e = entry; int i = index; Entry t[] = table; /* Use locals for faster loop iteration */ while (e == null && i > 0) e = t[--i]; entry = e; index = i; return e != null; } public Object next() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry et = entry; int i = index; Entry t[] = table; /* Use locals for faster loop iteration */ while (et == null && i > 0) et = t[--i]; entry = et; index = i; if (et != null) { Entry e = lastReturned = entry; entry = e.next; return type == KEYS ? e.key : (type == VALUES ? e.value : e); } throw new NoSuchElementException(); } public void remove() { if (lastReturned == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry[] tab = IdentityHashMap.this.table; int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) { if (e == lastReturned) { modCount++; expectedModCount++; if (prev == null) tab[index] = e.next; else prev.next = e.next; count--; lastReturned = null; return; } } throw new ConcurrentModificationException(); } } /** * Save the state of the IdentityHashMap instance to a stream (i.e., * serialize it). * * @serialData The capacity of the IdentityHashMap (the length of the * bucket array) is emitted (int), followed by the * size of the IdentityHashMap (the number of key-value * mappings), followed by the key (Object) and value (Object) * for each key-value mapping represented by the IdentityHashMap * The key-value mappings are emitted in no particular order. */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out the threshold, loadfactor, and any hidden stuff s.defaultWriteObject(); // Write out number of buckets s.writeInt(table.length); // Write out size (number of Mappings) s.writeInt(count); // Write out keys and values (alternating) for (int index = table.length - 1; index >= 0; index--) { Entry entry = table[index]; while (entry != null) { s.writeObject(entry.key); s.writeObject(entry.value); entry = entry.next; } } } /** * Reconstitute the IdentityHashMap instance from a stream (i.e., * deserialize it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in the threshold, loadfactor, and any hidden stuff s.defaultReadObject(); // Read in number of buckets and allocate the bucket array; int numBuckets = s.readInt(); table = new Entry[numBuckets]; // Read in size (number of Mappings) int size = s.readInt(); // Read the keys and values, and put the mappings in the IdentityHashMap for (int i = 0; i < size; i++) { Object key = s.readObject(); Object value = s.readObject(); put(key, value); } } int capacity() { return table.length; } float loadFactor() { return loadFactor; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/util/ModelFactory.java0000644000175000017500000000610411723544472025562 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.util; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateModel; /** * Interface used to create various wrapper models in the {@link ModelCache}. * @version $Id: ModelFactory.java,v 1.6 2003/01/12 23:40:16 revusky Exp $ * @author Attila Szegedi, szegedia at freemail dot hu */ public interface ModelFactory { /** * Create a wrapping model for the specified object that belongs to * the specified wrapper. */ TemplateModel create(Object object, ObjectWrapper wrapper); } libfreemarker-java-2.3.19.orig/src/freemarker/ext/util/ModelCache.java0000644000175000017500000001423611723544471025162 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Map; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelAdapter; /** * Internally used by various wrapper implementations to implement model * caching. * @version $Id: ModelCache.java,v 1.9 2003/01/12 23:40:15 revusky Exp $ * @author Attila Szegedi */ public abstract class ModelCache { private boolean useCache = false; private Map modelCache = null; private ReferenceQueue refQueue = null; protected ModelCache() { } /** * Sets whether this wrapper caches model instances. Default is false. * When set to true, calling {@link #getInstance(Object)} * multiple times for the same object will return the same model. */ public synchronized void setUseCache(boolean useCache) { this.useCache = useCache; if(useCache) { modelCache = new IdentityHashMap(); refQueue = new ReferenceQueue(); } else { modelCache = null; refQueue = null; } } public TemplateModel getInstance(Object object) { if(object instanceof TemplateModel) { return (TemplateModel)object; } if(object instanceof TemplateModelAdapter) { return ((TemplateModelAdapter)object).getTemplateModel(); } if(useCache && isCacheable(object)) { TemplateModel model = lookup(object); if(model == null) { model = create(object); register(model, object); } return model; } else { return create(object); } } protected abstract TemplateModel create(Object object); protected abstract boolean isCacheable(Object object); public void clearCache() { if(modelCache != null) { synchronized(modelCache) { modelCache.clear(); } } } private final TemplateModel lookup(Object object) { ModelReference ref = null; // NOTE: we're doing minimal synchronizations -- which can lead to // duplicate wrapper creation. However, this has no harmful side-effects and // is a lesser performance hit. synchronized (modelCache) { ref = (ModelReference) modelCache.get(object); } if (ref != null) return ref.getModel(); return null; } private final void register(TemplateModel model, Object object) { synchronized (modelCache) { // Remove cleared references for (;;) { ModelReference queuedRef = (ModelReference) refQueue.poll(); if (queuedRef == null) break; modelCache.remove(queuedRef.object); } // Register new reference modelCache.put(object, new ModelReference(model, object, refQueue)); } } /** * A special soft reference that is registered in the modelCache. * When it gets cleared (that is, the model became unreachable) * it will remove itself from the model cache. */ private static final class ModelReference extends SoftReference { Object object; ModelReference(TemplateModel ref, Object object, ReferenceQueue refQueue) { super(ref, refQueue); this.object = object; } TemplateModel getModel() { return (TemplateModel) this.get(); } } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/rhino/0000755000175000017500000000000012164627123022463 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/rhino/RhinoWrapper.java0000644000175000017500000000521411723544471025754 0ustar ebourgebourgpackage freemarker.ext.rhino; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.Undefined; import org.mozilla.javascript.UniqueTag; import org.mozilla.javascript.Wrapper; import freemarker.ext.beans.BeansWrapper; import freemarker.ext.util.ModelFactory; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: RhinoWrapper.java,v 1.2.2.1 2006/07/31 11:34:52 szegedia Exp $ */ public class RhinoWrapper extends BeansWrapper { // The type of the "instance" field changed between Rhino versions, so a // GETSTATIC with wrong type declaration would cause a NoSuchFieldError; // we're avoiding it by acquiring it reflectively. private static final Object UNDEFINED_INSTANCE; static { try { UNDEFINED_INSTANCE = AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws Exception { return Undefined.class.getField("instance").get(null); } }); } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new UndeclaredThrowableException(e); } } public TemplateModel wrap(Object obj) throws TemplateModelException { // So our existence builtins work as expected. if(obj == UNDEFINED_INSTANCE || obj == UniqueTag.NOT_FOUND) { return null; } // UniqueTag.NULL_VALUE represents intentionally set null in Rhino, and // BeansWrapper#nullModel also represents intentionally returned null. // I [A.Sz.] am fairly certain that this value is never passed out of // any of the Rhino code back to clients, but is instead always being // converted back to null. However, since this object is available to // any 3rd party Scriptable implementations as well, they might return // it, so we'll just be on the safe side, and handle it. if(obj == UniqueTag.NULL_VALUE) { return super.wrap(null); } // So, say, a JavaAdapter for FreeMarker interfaces works if(obj instanceof Wrapper) { obj = ((Wrapper)obj).unwrap(); } return super.wrap(obj); } protected ModelFactory getModelFactory(Class clazz) { if(Scriptable.class.isAssignableFrom(clazz)) { return RhinoScriptableModel.FACTORY; } return super.getModelFactory(clazz); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/rhino/RhinoFunctionModel.java0000644000175000017500000000246311723544471027105 0ustar ebourgebourgpackage freemarker.ext.rhino; import java.util.List; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import freemarker.ext.beans.BeansWrapper; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * @author Attila Szegedi * @version $Id: RhinoFunctionModel.java,v 1.2.2.1 2006/12/27 16:10:48 szegedia Exp $ */ public class RhinoFunctionModel extends RhinoScriptableModel implements TemplateMethodModelEx { private final Scriptable fnThis; public RhinoFunctionModel(Function function, Scriptable fnThis, BeansWrapper wrapper) { super(function, wrapper); this.fnThis = fnThis; } public Object exec(List arguments) throws TemplateModelException { Context cx = Context.getCurrentContext(); Object[] args = arguments.toArray(); BeansWrapper wrapper = getWrapper(); for (int i = 0; i < args.length; i++) { args[i] = wrapper.unwrap((TemplateModel)args[i]); } return wrapper.wrap(((Function)getScriptable()).call(cx, ScriptableObject.getTopLevelScope(fnThis), fnThis, args)); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/rhino/RhinoScriptableModel.java0000644000175000017500000000772211723544471027413 0ustar ebourgebourgpackage freemarker.ext.rhino; import org.mozilla.javascript.Context; import org.mozilla.javascript.EvaluatorException; import org.mozilla.javascript.Function; import org.mozilla.javascript.NativeJavaObject; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import freemarker.ext.beans.BeansWrapper; import freemarker.ext.util.ModelFactory; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; /** * @author Attila Szegedi * @version $Id: RhinoScriptableModel.java,v 1.4 2005/06/22 10:52:52 ddekany Exp $ */ public class RhinoScriptableModel implements TemplateHashModelEx, TemplateSequenceModel, AdapterTemplateModel, TemplateScalarModel, TemplateBooleanModel, TemplateNumberModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new RhinoScriptableModel((Scriptable)object, (BeansWrapper)wrapper); } }; private final Scriptable scriptable; private final BeansWrapper wrapper; public RhinoScriptableModel(Scriptable scriptable, BeansWrapper wrapper) { this.scriptable = scriptable; this.wrapper = wrapper; } public TemplateModel get(String key) throws TemplateModelException { Object retval = ScriptableObject.getProperty(scriptable, key); if(retval instanceof Function) { return new RhinoFunctionModel((Function)retval, scriptable, wrapper); } else { return wrapper.wrap(retval); } } public TemplateModel get(int index) throws TemplateModelException { Object retval = ScriptableObject.getProperty(scriptable, index); if(retval instanceof Function) { return new RhinoFunctionModel((Function)retval, scriptable, wrapper); } else { return wrapper.wrap(retval); } } public boolean isEmpty() { return scriptable.getIds().length == 0; } public TemplateCollectionModel keys() throws TemplateModelException { return (TemplateCollectionModel)wrapper.wrap(scriptable.getIds()); } public int size() { return scriptable.getIds().length; } public TemplateCollectionModel values() throws TemplateModelException { Object[] ids = scriptable.getIds(); Object[] values = new Object[ids.length]; for (int i = 0; i < values.length; i++) { Object id = ids[i]; if(id instanceof Number) { values[i] = ScriptableObject.getProperty(scriptable, ((Number)id).intValue()); } else { values[i] = ScriptableObject.getProperty(scriptable, String.valueOf(id)); } } return (TemplateCollectionModel)wrapper.wrap(values); } public boolean getAsBoolean() { return Context.toBoolean(scriptable); } public Number getAsNumber() { return new Double(Context.toNumber(scriptable)); } public String getAsString() { return Context.toString(scriptable); } Scriptable getScriptable() { return scriptable; } BeansWrapper getWrapper() { return wrapper; } public Object getAdaptedObject(Class hint) { try { return NativeJavaObject.coerceType(hint, scriptable); } catch(EvaluatorException e) { return NativeJavaObject.coerceType(Object.class, scriptable); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/rhino/package.html0000644000175000017500000000014111723544467024751 0ustar ebourgebourg

Rhino (ECMAScript) support

libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/0000755000175000017500000000000012164627123022434 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/EnumerationModel.java0000644000175000017500000001271411723544470026556 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.Enumeration; import java.util.NoSuchElementException; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; /** *

A class that adds {@link TemplateModelIterator} functionality to the * {@link Enumeration} interface implementers. *

Using the model as a collection model is NOT thread-safe, as * enumerations are inherently not thread-safe. * Further, you can iterate over it only once. Attempts to call the * {@link #iterator()} method after it was already driven to the end once will * throw an exception.

* @author Attila Szegedi * @version $Id: EnumerationModel.java,v 1.24 2003/06/03 13:21:32 szegedia Exp $ */ public class EnumerationModel extends BeanModel implements TemplateModelIterator, TemplateCollectionModel { private boolean accessed = false; /** * Creates a new model that wraps the specified enumeration object. * @param enumeration the enumeration object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public EnumerationModel(Enumeration enumeration, BeansWrapper wrapper) { super(enumeration, wrapper); } /** * This allows the enumeration to be used in a <foreach> block. * @return "this" */ public TemplateModelIterator iterator() throws TemplateModelException { synchronized(this) { if(accessed) { throw new TemplateModelException( "This collection is stateful and can not be iterated over the" + " second time."); } accessed = true; } return this; } /** * Calls underlying {@link Enumeration#nextElement()}. */ public boolean hasNext() { return ((Enumeration)object).hasMoreElements(); } /** * Calls underlying {@link Enumeration#nextElement()} and wraps the result. */ public TemplateModel next() throws TemplateModelException { try { return wrap(((Enumeration)object).nextElement()); } catch(NoSuchElementException e) { throw new TemplateModelException( "No more elements in the enumeration."); } } /** * Returns {@link Enumeration#hasMoreElements()}. Therefore, an * enumeration that has no more element evaluates to false, and an * enumeration that has further elements evaluates to true. */ public boolean getAsBoolean() { return hasNext(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/OverloadedMethodModel.java0000644000175000017500000001352511723544470027516 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import freemarker.template.SimpleNumber; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.Collections12; /** * A class that will wrap a reflected method call into a * {@link freemarker.template.TemplateMethodModel} interface. * It is used by {@link BeanModel} to wrap reflected method calls * for overloaded methods. * @author Attila Szegedi, szegedia at users dot sourceforge dot net * @version $Id: OverloadedMethodModel.java,v 1.25 2005/06/11 12:12:04 szegedia Exp $ */ class OverloadedMethodModel implements TemplateMethodModelEx, TemplateSequenceModel { private final Object object; private final MethodMap methodMap; public OverloadedMethodModel(Object object, MethodMap methodMap) { this.object = object; this.methodMap = methodMap; } /** * Invokes the method, passing it the arguments from the list. The actual * method to call from several overloaded methods will be chosen based * on the classes of the arguments. * @throws TemplateModelException if the method cannot be chosen * unambiguously. */ public Object exec(List arguments) throws TemplateModelException { MemberAndArguments maa = methodMap.getMemberAndArguments(arguments); Method method = (Method)maa.getMember(); try { return methodMap.getWrapper().invokeMethod(object, method, maa.getArgs()); } catch(Exception e) { while(e instanceof InvocationTargetException) { Throwable t = ((InvocationTargetException)e).getTargetException(); if(t instanceof Exception) { e = (Exception)t; } else { break; } } if((method.getModifiers() & Modifier.STATIC) != 0) { throw new TemplateModelException("Method " + method + " threw an exception", e); } else { StringBuffer buf = new StringBuffer(); Object[] args = maa.getArgs(); for(int i = 0; i < args.length; ++i) { Object arg = args[i]; buf.append(arg == null ? "null" : arg.getClass().getName()).append(','); } throw new TemplateModelException("Method " + method + " threw an exception when invoked on " + object + " with arguments of types [" + buf + "]", e); } } } public TemplateModel get(int index) throws TemplateModelException { return (TemplateModel) exec(Collections12.singletonList( new SimpleNumber(new Integer(index)))); } public int size() throws TemplateModelException { throw new TemplateModelException("?size is unsupported for: " + getClass().getName()); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/StaticModel.java0000644000175000017500000002203311723544467025520 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import freemarker.log.Logger; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * Wraps the static fields and methods of a class in a * {@link freemarker.template.TemplateHashModel}. * Fields are wrapped using {@link BeansWrapper#wrap(Object)}, and * methods are wrapped into an appropriate {@link freemarker.template.TemplateMethodModelEx} instance. * Unfortunately, there is currently no support for bean property-style * calls of static methods, similar to that in {@link BeanModel}. * @author Attila Szegedi * @version $Id: StaticModel.java,v 1.24.2.1 2006/11/12 10:23:02 szegedia Exp $ */ final class StaticModel implements TemplateHashModelEx { private static final Logger logger = Logger.getLogger("freemarker.beans"); private final Class clazz; private final BeansWrapper wrapper; private final Map map = new HashMap(); StaticModel(Class clazz, BeansWrapper wrapper) throws TemplateModelException { this.clazz = clazz; this.wrapper = wrapper; populate(); } /** * Returns the field or method named by the key * parameter. */ public TemplateModel get(String key) throws TemplateModelException { Object model = map.get(key); // Simple method, overloaded method or final field -- these have cached // template models if (model instanceof TemplateModel) return (TemplateModel) model; // Non-final field; this must be evaluated on each call. if (model instanceof Field) { try { return wrapper.getOuterIdentity().wrap(((Field) model).get(null)); } catch (IllegalAccessException e) { throw new TemplateModelException( "Illegal access for field " + key + " of class " + clazz.getName()); } } throw new TemplateModelException( "No such key: " + key + " in class " + clazz.getName()); } /** * Returns true if there is at least one public static * field or method in the underlying class. */ public boolean isEmpty() { return map.isEmpty(); } public int size() { return map.size(); } public TemplateCollectionModel keys() throws TemplateModelException { return (TemplateCollectionModel)wrapper.getOuterIdentity().wrap(map.keySet()); } public TemplateCollectionModel values() throws TemplateModelException { return (TemplateCollectionModel)wrapper.getOuterIdentity().wrap(map.values()); } private void populate() throws TemplateModelException { if (!Modifier.isPublic(clazz.getModifiers())) { throw new TemplateModelException( "Can't wrap the non-public class " + clazz.getName()); } if(wrapper.getExposureLevel() == BeansWrapper.EXPOSE_NOTHING) { return; } Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; ++i) { Field field = fields[i]; int mod = field.getModifiers(); if (Modifier.isPublic(mod) && Modifier.isStatic(mod)) { if (Modifier.isFinal(mod)) try { // public static final fields are evaluated once and // stored in the map map.put(field.getName(), wrapper.getOuterIdentity().wrap(field.get(null))); } catch (IllegalAccessException e) { // Intentionally ignored } else // This is a special flagging value: Field in the map means // that this is a non-final field, and it must be evaluated // on each get() call. map.put(field.getName(), field); } } if(wrapper.getExposureLevel() < BeansWrapper.EXPOSE_PROPERTIES_ONLY) { Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; ++i) { Method method = methods[i]; int mod = method.getModifiers(); if (Modifier.isPublic(mod) && Modifier.isStatic(mod) && wrapper.isSafeMethod(method)) { String name = method.getName(); Object obj = map.get(name); if (obj instanceof Method) { MethodMap methodMap = new MethodMap(name, wrapper); methodMap.addMember((Method) obj); methodMap.addMember(method); map.put(name, methodMap); } else if(obj instanceof MethodMap) { MethodMap methodMap = (MethodMap) obj; methodMap.addMember(method); } else { if(obj != null) { logger.info("Overwriting value [" + obj + "] for " + " key '" + name + "' with [" + method + "] in static model for " + clazz.getName()); } map.put(name, method); } } } for (Iterator entries = map.entrySet().iterator(); entries.hasNext();) { Map.Entry entry = (Map.Entry) entries.next(); Object value = entry.getValue(); if (value instanceof Method) { Method method = (Method)value; entry.setValue(new SimpleMethodModel(null, method, method.getParameterTypes(), wrapper)); } else if (value instanceof MethodMap) { entry.setValue(new OverloadedMethodModel(null, (MethodMap)value)); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/MemberAndArguments.java0000644000175000017500000000074311723544471027027 0ustar ebourgebourgpackage freemarker.ext.beans; import java.lang.reflect.Member; /** * @author Attila Szegedi * @version $Id: $ */ class MemberAndArguments { private final Member member; private final Object[] args; MemberAndArguments(Member member, Object[] args) { this.member = member; this.args = args; } Object[] getArgs() { return args; } public Member getMember() { return member; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/BeansModelCache.java0000644000175000017500000000272211723544471026243 0ustar ebourgebourgpackage freemarker.ext.beans; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import freemarker.ext.util.ModelCache; import freemarker.ext.util.ModelFactory; import freemarker.template.TemplateModel; public class BeansModelCache extends ModelCache { private final Map classToFactory = new HashMap(); private final Set mappedClassNames = new HashSet(); private final BeansWrapper wrapper; BeansModelCache(BeansWrapper wrapper) { this.wrapper = wrapper; } protected boolean isCacheable(Object object) { return object.getClass() != Boolean.class; } protected TemplateModel create(Object object) { Class clazz = object.getClass(); ModelFactory factory; synchronized(classToFactory) { factory = (ModelFactory)classToFactory.get(clazz); if(factory == null) { String className = clazz.getName(); // clear mappings when class reloading is detected if(!mappedClassNames.add(className)) { classToFactory.clear(); mappedClassNames.clear(); mappedClassNames.add(className); } factory = wrapper.getModelFactory(clazz); classToFactory.put(clazz, factory); } } return factory.create(object, wrapper); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/StaticModels.java0000644000175000017500000000656511723544471025712 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * Utility class for instantiating {@link StaticModel} instances from * templates. If your template's data model contains an instance of * StaticModels (named, say StaticModels), then you can * instantiate an arbitrary StaticModel using get syntax (i.e. * StaticModels["java.lang.System"].currentTimeMillis()). * @author Attila Szegedi * @version $Id: StaticModels.java,v 1.12.4.1 2006/11/12 10:23:02 szegedia Exp $ */ class StaticModels extends ClassBasedModelFactory { StaticModels(BeansWrapper wrapper) { super(wrapper); } protected TemplateModel createModel(Class clazz) throws TemplateModelException { return new StaticModel(clazz, getWrapper()); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/BeansWrapper.java0000644000175000017500000020627011723544471025703 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.beans.BeanInfo; import java.beans.IndexedPropertyDescriptor; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; import java.io.InputStream; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.ResourceBundle; import java.util.Set; import java.util.StringTokenizer; import freemarker.ext.util.IdentityHashMap; import freemarker.ext.util.ModelCache; import freemarker.ext.util.ModelFactory; import freemarker.ext.util.WrapperTemplateModel; import freemarker.log.Logger; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.Collections12; import freemarker.template.utility.SecurityUtilities; import freemarker.template.utility.UndeclaredThrowableException; /** * Utility class that provides generic services to reflection classes. * It handles all polymorphism issues in the {@link #wrap(Object)} and {@link #unwrap(TemplateModel)} methods. * @author Attila Szegedi * @version $Id: BeansWrapper.java,v 1.91.2.13 2007/04/02 13:08:59 szegedia Exp $ */ public class BeansWrapper implements ObjectWrapper { static final Object CAN_NOT_UNWRAP = new Object(); private static final Class BIGINTEGER_CLASS = java.math.BigInteger.class; private static final Class BOOLEAN_CLASS = Boolean.class; private static final Class CHARACTER_CLASS = Character.class; private static final Class COLLECTION_CLASS = Collection.class; private static final Class DATE_CLASS = Date.class; private static final Class HASHADAPTER_CLASS = HashAdapter.class; private static final Class ITERABLE_CLASS; private static final Class LIST_CLASS = List.class; private static final Class MAP_CLASS = Map.class; private static final Class NUMBER_CLASS = Number.class; private static final Class OBJECT_CLASS = Object.class; private static final Class SEQUENCEADAPTER_CLASS = SequenceAdapter.class; private static final Class SET_CLASS = Set.class; private static final Class SETADAPTER_CLASS = SetAdapter.class; private static final Class STRING_CLASS = String.class; static { Class iterable; try { iterable = Class.forName("java.lang.Iterable"); } catch(ClassNotFoundException e) { // We're running on a pre-1.5 JRE iterable = null; } ITERABLE_CLASS = iterable; } // When this property is true, some things are stricter. This is mostly to // catch anomalous things in development that can otherwise be valid situations // for our users. private static final boolean DEVELOPMENT = "true".equals(SecurityUtilities.getSystemProperty("freemarker.development")); private static final Constructor ENUMS_MODEL_CTOR = enumsModelCtor(); private static final Logger logger = Logger.getLogger("freemarker.beans"); private static final Set UNSAFE_METHODS = createUnsafeMethodsSet(); static final Object GENERIC_GET_KEY = new Object(); private static final Object CONSTRUCTORS = new Object(); private static final Object ARGTYPES = new Object(); private static final boolean javaRebelAvailable = isJavaRebelAvailable(); /** * The default instance of BeansWrapper */ private static final BeansWrapper INSTANCE = new BeansWrapper(); // Cache of hash maps that contain already discovered properties and methods // for a specified class. Each key is a Class, each value is a hash map. In // that hash map, each key is a property/method name, each value is a // MethodDescriptor or a PropertyDescriptor assigned to that property/method. private final Map classCache = new HashMap(); private Set cachedClassNames = new HashSet(); private final StaticModels staticModels = new StaticModels(this); private final ClassBasedModelFactory enumModels = createEnumModels(this); private final ModelCache modelCache = new BeansModelCache(this); private final BooleanModel FALSE = new BooleanModel(Boolean.FALSE, this); private final BooleanModel TRUE = new BooleanModel(Boolean.TRUE, this); /** * At this level of exposure, all methods and properties of the * wrapped objects are exposed to the template. */ public static final int EXPOSE_ALL = 0; /** * At this level of exposure, all methods and properties of the wrapped * objects are exposed to the template except methods that are deemed * not safe. The not safe methods are java.lang.Object methods wait() and * notify(), java.lang.Class methods getClassLoader() and newInstance(), * java.lang.reflect.Method and java.lang.reflect.Constructor invoke() and * newInstance() methods, all java.lang.reflect.Field set methods, all * java.lang.Thread and java.lang.ThreadGroup methods that can change its * state, as well as the usual suspects in java.lang.System and * java.lang.Runtime. */ public static final int EXPOSE_SAFE = 1; /** * At this level of exposure, only property getters are exposed. * Additionally, property getters that map to unsafe methods are not * exposed (i.e. Class.classLoader and Thread.contextClassLoader). */ public static final int EXPOSE_PROPERTIES_ONLY = 2; /** * At this level of exposure, no bean properties and methods are exposed. * Only map items, resource bundle items, and objects retrieved through * the generic get method (on objects of classes that have a generic get * method) can be retrieved through the hash interface. You might want to * call {@link #setMethodsShadowItems(boolean)} with false value to * speed up map item retrieval. */ public static final int EXPOSE_NOTHING = 3; private int exposureLevel = EXPOSE_SAFE; private TemplateModel nullModel = null; private boolean methodsShadowItems = true; private boolean exposeFields = false; private int defaultDateType = TemplateDateModel.UNKNOWN; private ObjectWrapper outerIdentity = this; private boolean simpleMapWrapper; private boolean strict = false; /** * Creates a new instance of BeansWrapper. The newly created instance * will use the null reference as its null object, it will use * {@link #EXPOSE_SAFE} method exposure level, and will not cache * model instances. */ public BeansWrapper() { if(javaRebelAvailable) { JavaRebelIntegration.registerWrapper(this); } } /** * @see #setStrict(boolean) */ public boolean isStrict() { return strict; } /** * Specifies if an attempt to read a bean property that doesn't exist in the * wrapped object should throw an {@link InvalidPropertyException}. * *

If this property is false (the default) then an attempt to read * a missing bean property is the same as reading an existing bean property whose * value is null. The template can't tell the difference, and thus always * can use ?default('something') and ?exists and similar built-ins * to handle the situation. * *

If this property is true then an attempt to read a bean propertly in * the template (like myBean.aProperty) that doesn't exist in the bean * object (as opposed to just holding null value) will cause * {@link InvalidPropertyException}, which can't be suppressed in the template * (not even with myBean.noSuchProperty?default('something')). This way * ?default('something') and ?exists and similar built-ins can be used to * handle existing properties whose value is null, without the risk of * hiding typos in the property names. Typos will always cause error. But mind you, it * goes against the basic approach of FreeMarker, so use this feature only if you really * know what are you doing. */ public void setStrict(boolean strict) { this.strict = strict; } /** * When wrapping an object, the BeansWrapper commonly needs to wrap * "sub-objects", for example each element in a wrapped collection. * Normally it wraps these objects using itself. However, this makes * it difficult to delegate to a BeansWrapper as part of a custom * aggregate ObjectWrapper. This method lets you set the ObjectWrapper * which will be used to wrap the sub-objects. * @param outerIdentity the aggregate ObjectWrapper */ public void setOuterIdentity(ObjectWrapper outerIdentity) { this.outerIdentity = outerIdentity; } /** * By default returns this. * @see #setOuterIdentity(ObjectWrapper) */ public ObjectWrapper getOuterIdentity() { return outerIdentity; } /** * By default the BeansWrapper wraps classes implementing * java.util.Map using {@link MapModel}. Setting this flag will * cause it to use a {@link SimpleMapModel} instead. The biggest * difference is that when using a {@link SimpleMapModel}, the * map will be visible as TemplateHashModelEx, * and the subvariables will be the content of the map, * without the other methods and properties of the map object. * @param simpleMapWrapper enable simple map wrapping */ public void setSimpleMapWrapper(boolean simpleMapWrapper) { this.simpleMapWrapper = simpleMapWrapper; } /** * Tells whether Maps are exposed as simple maps, without access to their * method. See {@link #setSimpleMapWrapper(boolean)} for details. * @return true if Maps are exposed as simple hashes, false if they're * exposed as full JavaBeans. */ public boolean isSimpleMapWrapper() { return simpleMapWrapper; } /** * Sets the method exposure level. By default, set to EXPOSE_SAFE. * @param exposureLevel can be any of the EXPOSE_xxx * constants. */ public void setExposureLevel(int exposureLevel) { if(exposureLevel < EXPOSE_ALL || exposureLevel > EXPOSE_NOTHING) { throw new IllegalArgumentException("Illegal exposure level " + exposureLevel); } this.exposureLevel = exposureLevel; } int getExposureLevel() { return exposureLevel; } /** * Controls whether public instance fields of classes are exposed to * templates. * @param exposeFields if set to true, public instance fields of classes * that do not have a property getter defined can be accessed directly by * their name. If there is a property getter for a property of the same * name as the field (i.e. getter "getFoo()" and field "foo"), then * referring to "foo" in template invokes the getter. If set to false, no * access to public instance fields of classes is given. Default is false. */ public void setExposeFields(boolean exposeFields) { this.exposeFields = exposeFields; } /** * Returns whether exposure of public instance fields of classes is * enabled. See {@link #setExposeFields(boolean)} for details. * @return true if public instance fields are exposed, false otherwise. */ public boolean isExposeFields() { return exposeFields; } /** * Sets whether methods shadow items in beans. When true (this is the * default value), ${object.name} will first try to locate * a bean method or property with the specified name on the object, and * only if it doesn't find it will it try to call * object.get(name), the so-called "generic get method" that * is usually used to access items of a container (i.e. elements of a map). * When set to false, the lookup order is reversed and generic get method * is called first, and only if it returns null is method lookup attempted. */ public synchronized void setMethodsShadowItems(boolean methodsShadowItems) { this.methodsShadowItems = methodsShadowItems; } boolean isMethodsShadowItems() { return methodsShadowItems; } /** * Sets the default date type to use for date models that result from * a plain java.util.Date instead of java.sql.Date or * java.sql.Time or java.sql.Timestamp. Default value is * {@link TemplateDateModel#UNKNOWN}. * @param defaultDateType the new default date type. */ public synchronized void setDefaultDateType(int defaultDateType) { this.defaultDateType = defaultDateType; } /** * Returns the default date type. See {@link #setDefaultDateType(int)} for * details. * @return the default date type */ protected int getDefaultDateType() { return defaultDateType; } /** * Sets whether this wrapper caches model instances. Default is false. * When set to true, calling {@link #wrap(Object)} multiple times for * the same object will likely return the same model (although there is * no guarantee as the cache items can be cleared anytime). */ public void setUseCache(boolean useCache) { modelCache.setUseCache(useCache); } /** * Sets the null model. This model is returned from the * {@link #wrap(Object)} method whenever the underlying object * reference is null. It defaults to null reference, which is dealt * with quite strictly on engine level, however you can substitute an * arbitrary (perhaps more lenient) model, such as * {@link freemarker.template.TemplateScalarModel#EMPTY_STRING}. */ public void setNullModel(TemplateModel nullModel) { this.nullModel = nullModel; } /** * Returns the default instance of the wrapper. This instance is used * when you construct various bean models without explicitly specifying * a wrapper. It is also returned by * {@link freemarker.template.ObjectWrapper#BEANS_WRAPPER} * and this is the sole instance that is used by the JSP adapter. * You can modify the properties of the default instance (caching, * exposure level, null model) to affect its operation. By default, the * default instance is not caching, uses the EXPOSE_SAFE * exposure level, and uses null reference as the null model. */ public static final BeansWrapper getDefaultInstance() { return INSTANCE; } /** * Wraps the object with a template model that is most specific for the object's * class. Specifically: *

    *
  • if the object is null, returns the {@link #setNullModel(TemplateModel) null model},
  • *
  • if the object is a Number returns a {@link NumberModel} for it,
  • *
  • if the object is a Date returns a {@link DateModel} for it,
  • *
  • if the object is a Boolean returns * {@link freemarker.template.TemplateBooleanModel#TRUE} or * {@link freemarker.template.TemplateBooleanModel#FALSE}
  • *
  • if the object is already a TemplateModel, returns it unchanged,
  • *
  • if the object is an array, returns a {@link ArrayModel} for it *
  • if the object is a Map, returns a {@link MapModel} for it *
  • if the object is a Collection, returns a {@link CollectionModel} for it *
  • if the object is an Iterator, returns a {@link IteratorModel} for it *
  • if the object is an Enumeration, returns a {@link EnumerationModel} for it *
  • if the object is a String, returns a {@link StringModel} for it *
  • otherwise, returns a generic {@link BeanModel} for it. *
*/ public TemplateModel wrap(Object object) throws TemplateModelException { if(object == null) return nullModel; return modelCache.getInstance(object); } /** * @deprecated override {@link #getModelFactory(Class)} instead. Using this * method will now bypass wrapper caching (if it is enabled) and always * result in creation of a new wrapper. This method will be removed in 2.4 * @param object * @param factory */ protected TemplateModel getInstance(Object object, ModelFactory factory) { return factory.create(object, this); } private final ModelFactory BOOLEAN_FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return ((Boolean)object).booleanValue() ? TRUE : FALSE; } }; private static final ModelFactory ITERATOR_FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new IteratorModel((Iterator)object, (BeansWrapper)wrapper); } }; private static final ModelFactory ENUMERATION_FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new EnumerationModel((Enumeration)object, (BeansWrapper)wrapper); } }; protected ModelFactory getModelFactory(Class clazz) { if(Map.class.isAssignableFrom(clazz)) { return simpleMapWrapper ? SimpleMapModel.FACTORY : MapModel.FACTORY; } if(Collection.class.isAssignableFrom(clazz)) { return CollectionModel.FACTORY; } if(Number.class.isAssignableFrom(clazz)) { return NumberModel.FACTORY; } if(Date.class.isAssignableFrom(clazz)) { return DateModel.FACTORY; } if(Boolean.class == clazz) { // Boolean is final return BOOLEAN_FACTORY; } if(ResourceBundle.class.isAssignableFrom(clazz)) { return ResourceBundleModel.FACTORY; } if(Iterator.class.isAssignableFrom(clazz)) { return ITERATOR_FACTORY; } if(Enumeration.class.isAssignableFrom(clazz)) { return ENUMERATION_FACTORY; } if(clazz.isArray()) { return ArrayModel.FACTORY; } return StringModel.FACTORY; } /** * Attempts to unwrap a model into underlying object. Generally, this * method is the inverse of the {@link #wrap(Object)} method. In addition * it will unwrap arbitrary {@link TemplateNumberModel} instances into * a number, arbitrary {@link TemplateDateModel} instances into a date, * {@link TemplateScalarModel} instances into a String, arbitrary * {@link TemplateBooleanModel} instances into a Boolean, arbitrary * {@link TemplateHashModel} instances into a Map, arbitrary * {@link TemplateSequenceModel} into a List, and arbitrary * {@link TemplateCollectionModel} into a Set. All other objects are * returned unchanged. * @throws TemplateModelException if an attempted unwrapping fails. */ public Object unwrap(TemplateModel model) throws TemplateModelException { return unwrap(model, OBJECT_CLASS); } /** * Attempts to unwrap a model into an object of the desired class. * Generally, this method is the inverse of the {@link #wrap(Object)} * method. It recognizes a wide range of hint classes - all Java built-in * primitives, primitive wrappers, numbers, dates, sets, lists, maps, and * native arrays. * @param model the model to unwrap * @param hint the class of the unwrapped result * @return the unwrapped result of the desired class * @throws TemplateModelException if an attempted unwrapping fails. */ public Object unwrap(TemplateModel model, Class hint) throws TemplateModelException { final Object obj = unwrapInternal(model, hint); if(obj == CAN_NOT_UNWRAP) { throw new TemplateModelException("Can not unwrap model of type " + model.getClass().getName() + " to type " + hint.getName()); } return obj; } Object unwrapInternal(TemplateModel model, Class hint) throws TemplateModelException { return unwrap(model, hint, null); } private Object unwrap(TemplateModel model, Class hint, Map recursionStops) throws TemplateModelException { if(model == null || model == nullModel) { return null; } boolean isBoolean = Boolean.TYPE == hint; boolean isChar = Character.TYPE == hint; // This is for transparent interop with other wrappers (and ourselves) // Passing the hint allows i.e. a Jython-aware method that declares a // PyObject as its argument to receive a PyObject from a JythonModel // passed as an argument to TemplateMethodModelEx etc. if(model instanceof AdapterTemplateModel) { Object adapted = ((AdapterTemplateModel)model).getAdaptedObject( hint); if(hint.isInstance(adapted)) { return adapted; } // Attempt numeric conversion if(adapted instanceof Number && ((hint.isPrimitive() && !isChar && !isBoolean) || NUMBER_CLASS.isAssignableFrom(hint))) { Number number = convertUnwrappedNumber(hint, (Number)adapted); if(number != null) { return number; } } } if(model instanceof WrapperTemplateModel) { Object wrapped = ((WrapperTemplateModel)model).getWrappedObject(); if(hint.isInstance(wrapped)) { return wrapped; } // Attempt numeric conversion if(wrapped instanceof Number && ((hint.isPrimitive() && !isChar && !isBoolean) || NUMBER_CLASS.isAssignableFrom(hint))) { Number number = convertUnwrappedNumber(hint, (Number)wrapped); if(number != null) { return number; } } } // Translation of generic template models to POJOs. First give priority // to various model interfaces based on the hint class. This helps us // select the appropriate interface in multi-interface models when we // know what is expected as the return type. if(STRING_CLASS == hint) { if(model instanceof TemplateScalarModel) { return ((TemplateScalarModel)model).getAsString(); } // String is final, so no other conversion will work return CAN_NOT_UNWRAP; } // Primitive numeric types & Number.class and its subclasses if((hint.isPrimitive() && !isChar && !isBoolean) || NUMBER_CLASS.isAssignableFrom(hint)) { if(model instanceof TemplateNumberModel) { Number number = convertUnwrappedNumber(hint, ((TemplateNumberModel)model).getAsNumber()); if(number != null) { return number; } } } if(isBoolean || BOOLEAN_CLASS == hint) { if(model instanceof TemplateBooleanModel) { return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; } // Boolean is final, no other conversion will work return CAN_NOT_UNWRAP; } if(MAP_CLASS == hint) { if(model instanceof TemplateHashModel) { return new HashAdapter((TemplateHashModel)model, this); } } if(LIST_CLASS == hint) { if(model instanceof TemplateSequenceModel) { return new SequenceAdapter((TemplateSequenceModel)model, this); } } if(SET_CLASS == hint) { if(model instanceof TemplateCollectionModel) { return new SetAdapter((TemplateCollectionModel)model, this); } } if(COLLECTION_CLASS == hint || ITERABLE_CLASS == hint) { if(model instanceof TemplateCollectionModel) { return new CollectionAdapter((TemplateCollectionModel)model, this); } if(model instanceof TemplateSequenceModel) { return new SequenceAdapter((TemplateSequenceModel)model, this); } } // TemplateSequenceModels can be converted to arrays if(hint.isArray()) { if(model instanceof TemplateSequenceModel) { if(recursionStops != null) { Object retval = recursionStops.get(model); if(retval != null) { return retval; } } else { recursionStops = new IdentityHashMap(); } TemplateSequenceModel seq = (TemplateSequenceModel)model; Class componentType = hint.getComponentType(); Object array = Array.newInstance(componentType, seq.size()); recursionStops.put(model, array); try { int size = seq.size(); for (int i = 0; i < size; i++) { Object val = unwrap(seq.get(i), componentType, recursionStops); if(val == CAN_NOT_UNWRAP) { return CAN_NOT_UNWRAP; } Array.set(array, i, val); } } finally { recursionStops.remove(model); } return array; } // array classes are final, no other conversion will work return CAN_NOT_UNWRAP; } // Allow one-char strings to be coerced to characters if(isChar || hint == CHARACTER_CLASS) { if(model instanceof TemplateScalarModel) { String s = ((TemplateScalarModel)model).getAsString(); if(s.length() == 1) { return new Character(s.charAt(0)); } } // Character is final, no other conversion will work return CAN_NOT_UNWRAP; } if(DATE_CLASS.isAssignableFrom(hint)) { if(model instanceof TemplateDateModel) { Date date = ((TemplateDateModel)model).getAsDate(); if(hint.isInstance(date)) { return date; } } } // Translation of generic template models to POJOs. Since hint was of // no help initially, now use an admittedly arbitrary order of // interfaces. Note we still test for isInstance and isAssignableFrom // to guarantee we return a compatible value. if(model instanceof TemplateNumberModel) { Number number = ((TemplateNumberModel)model).getAsNumber(); if(hint.isInstance(number)) { return number; } } if(model instanceof TemplateDateModel) { Date date = ((TemplateDateModel)model).getAsDate(); if(hint.isInstance(date)) { return date; } } if(model instanceof TemplateScalarModel && hint.isAssignableFrom(STRING_CLASS)) { return ((TemplateScalarModel)model).getAsString(); } if(model instanceof TemplateBooleanModel && hint.isAssignableFrom(BOOLEAN_CLASS)) { return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; } if(model instanceof TemplateHashModel && hint.isAssignableFrom( HASHADAPTER_CLASS)) { return new HashAdapter((TemplateHashModel)model, this); } if(model instanceof TemplateSequenceModel && hint.isAssignableFrom(SEQUENCEADAPTER_CLASS)) { return new SequenceAdapter((TemplateSequenceModel)model, this); } if(model instanceof TemplateCollectionModel && hint.isAssignableFrom(SETADAPTER_CLASS)) { return new SetAdapter((TemplateCollectionModel)model, this); } // Last ditch effort - is maybe the model itself instance of the // required type? if(hint.isInstance(model)) { return model; } return CAN_NOT_UNWRAP; } private static Number convertUnwrappedNumber(Class hint, Number number) { if(hint == Integer.TYPE || hint == Integer.class) { return number instanceof Integer ? (Integer)number : new Integer(number.intValue()); } if(hint == Long.TYPE || hint == Long.class) { return number instanceof Long ? (Long)number : new Long(number.longValue()); } if(hint == Float.TYPE || hint == Float.class) { return number instanceof Float ? (Float)number : new Float(number.floatValue()); } if(hint == Double.TYPE || hint == Double.class) { return number instanceof Double ? (Double)number : new Double(number.doubleValue()); } if(hint == Byte.TYPE || hint == Byte.class) { return number instanceof Byte ? (Byte)number : new Byte(number.byteValue()); } if(hint == Short.TYPE || hint == Short.class) { return number instanceof Short ? (Short)number : new Short(number.shortValue()); } if(hint == BigInteger.class) { return number instanceof BigInteger ? number : new BigInteger(number.toString()); } if(hint == BigDecimal.class) { if(number instanceof BigDecimal) { return number; } if(number instanceof BigInteger) { return new BigDecimal((BigInteger)number); } if(number instanceof Long) { // Because we can't represent long accurately as a // double return new BigDecimal(number.toString()); } return new BigDecimal(number.doubleValue()); } // Handle nonstandard Number subclasses as well as directly // java.lang.Number too if(hint.isInstance(number)) { return number; } return null; } /** * Invokes the specified method, wrapping the return value. The specialty * of this method is that if the return value is null, and the return type * of the invoked method is void, {@link TemplateModel#NOTHING} is returned. * @param object the object to invoke the method on * @param method the method to invoke * @param args the arguments to the method * @return the wrapped return value of the method. * @throws InvocationTargetException if the invoked method threw an exception * @throws IllegalAccessException if the method can't be invoked due to an * access restriction. * @throws TemplateModelException if the return value couldn't be wrapped * (this can happen if the wrapper has an outer identity or is subclassed, * and the outer identity or the subclass throws an exception. Plain * BeansWrapper never throws TemplateModelException). */ TemplateModel invokeMethod(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException, TemplateModelException { Object retval = method.invoke(object, args); return method.getReturnType() == Void.TYPE ? TemplateModel.NOTHING : getOuterIdentity().wrap(retval); } /** * Returns a hash model that represents the so-called class static models. * Every class static model is itself a hash through which you can call * static methods on the specified class. To obtain a static model for a * class, get the element of this hash with the fully qualified class name. * For example, if you place this hash model inside the root data model * under name "statics", you can use i.e. statics["java.lang. * System"]. currentTimeMillis() to call the {@link * java.lang.System#currentTimeMillis()} method. * @return a hash model whose keys are fully qualified class names, and * that returns hash models whose elements are the static models of the * classes. */ public TemplateHashModel getStaticModels() { return staticModels; } /** * Returns a hash model that represents the so-called class enum models. * Every class' enum model is itself a hash through which you can access * enum value declared by the specified class, assuming that class is an * enumeration. To obtain an enum model for a class, get the element of this * hash with the fully qualified class name. For example, if you place this * hash model inside the root data model under name "enums", you can use * i.e. statics["java.math.RoundingMode"].UP to access the * {@link java.math.RoundingMode#UP} value. * @return a hash model whose keys are fully qualified class names, and * that returns hash models whose elements are the enum models of the * classes. * @throws UnsupportedOperationException if this method is invoked on a * pre-1.5 JRE, as Java enums aren't supported there. */ public TemplateHashModel getEnumModels() { if(enumModels == null) { throw new UnsupportedOperationException( "Enums not supported on pre-1.5 JRE"); } return enumModels; } public Object newInstance(Class clazz, List arguments) throws TemplateModelException { try { introspectClass(clazz); Map classInfo = (Map)classCache.get(clazz); Object ctors = classInfo.get(CONSTRUCTORS); if(ctors == null) { throw new TemplateModelException("Class " + clazz.getName() + " has no public constructors."); } Constructor ctor = null; Object[] objargs; if(ctors instanceof SimpleMemberModel) { SimpleMemberModel smm = (SimpleMemberModel)ctors; ctor = (Constructor)smm.getMember(); objargs = smm.unwrapArguments(arguments, this); } else if(ctors instanceof MethodMap) { MethodMap methodMap = (MethodMap)ctors; MemberAndArguments maa = methodMap.getMemberAndArguments(arguments); objargs = maa.getArgs(); ctor = (Constructor)maa.getMember(); } else { // Cannot happen throw new Error(); } return ctor.newInstance(objargs); } catch (TemplateModelException e) { throw e; } catch (Exception e) { throw new TemplateModelException( "Could not create instance of class " + clazz.getName(), e); } } void introspectClass(Class clazz) { synchronized(classCache) { if(!classCache.containsKey(clazz)) { introspectClassInternal(clazz); } } } void removeIntrospectionInfo(Class clazz) { synchronized(classCache) { classCache.remove(clazz); staticModels.removeIntrospectionInfo(clazz); if(enumModels != null) { enumModels.removeIntrospectionInfo(clazz); } cachedClassNames.remove(clazz.getName()); synchronized(this) { modelCache.clearCache(); } } } private void introspectClassInternal(Class clazz) { String className = clazz.getName(); if(cachedClassNames.contains(className)) { if(logger.isInfoEnabled()) { logger.info("Detected a reloaded class [" + className + "]. Clearing BeansWrapper caches."); } // Class reload detected, throw away caches classCache.clear(); cachedClassNames = new HashSet(); synchronized(this) { modelCache.clearCache(); } staticModels.clearCache(); if(enumModels != null) { enumModels.clearCache(); } } classCache.put(clazz, populateClassMap(clazz)); cachedClassNames.add(className); } Map getClassKeyMap(Class clazz) { Map map; synchronized(classCache) { map = (Map)classCache.get(clazz); if(map == null) { introspectClassInternal(clazz); map = (Map)classCache.get(clazz); } } return map; } /** * Returns the number of introspected methods/properties that should * be available via the TemplateHashModel interface. Affected by the * {@link #setMethodsShadowItems(boolean)} and {@link * #setExposureLevel(int)} settings. */ int keyCount(Class clazz) { Map map = getClassKeyMap(clazz); int count = map.size(); if (map.containsKey(CONSTRUCTORS)) count--; if (map.containsKey(GENERIC_GET_KEY)) count--; if (map.containsKey(ARGTYPES)) count--; return count; } /** * Returns the Set of names of introspected methods/properties that * should be available via the TemplateHashModel interface. Affected * by the {@link #setMethodsShadowItems(boolean)} and {@link * #setExposureLevel(int)} settings. */ Set keySet(Class clazz) { Set set = new HashSet(getClassKeyMap(clazz).keySet()); set.remove(CONSTRUCTORS); set.remove(GENERIC_GET_KEY); set.remove(ARGTYPES); return set; } /** * Populates a map with property and method descriptors for a specified * class. If any property or method descriptors specifies a read method * that is not accessible, replaces it with appropriate accessible method * from a superclass or interface. */ private Map populateClassMap(Class clazz) { // Populate first from bean info Map map = populateClassMapWithBeanInfo(clazz); // Next add constructors try { Constructor[] ctors = clazz.getConstructors(); if(ctors.length == 1) { Constructor ctor = ctors[0]; map.put(CONSTRUCTORS, new SimpleMemberModel(ctor, ctor.getParameterTypes())); } else if(ctors.length > 1) { MethodMap ctorMap = new MethodMap("", this); for (int i = 0; i < ctors.length; i++) { ctorMap.addMember(ctors[i]); } map.put(CONSTRUCTORS, ctorMap); } } catch(SecurityException e) { logger.warn("Canont discover constructors for class " + clazz.getName(), e); } switch(map.size()) { case 0: { map = Collections12.EMPTY_MAP; break; } case 1: { Map.Entry e = (Map.Entry)map.entrySet().iterator().next(); map = Collections12.singletonMap(e.getKey(), e.getValue()); break; } } return map; } private Map populateClassMapWithBeanInfo(Class clazz) { Map classMap = new HashMap(); if(exposeFields) { Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; if((field.getModifiers() & Modifier.STATIC) == 0) { classMap.put(field.getName(), field); } } } Map accessibleMethods = discoverAccessibleMethods(clazz); Method genericGet = getFirstAccessibleMethod( MethodSignature.GET_STRING_SIGNATURE, accessibleMethods); if(genericGet == null) { genericGet = getFirstAccessibleMethod( MethodSignature.GET_OBJECT_SIGNATURE, accessibleMethods); } if(genericGet != null) { classMap.put(GENERIC_GET_KEY, genericGet); } if(exposureLevel == EXPOSE_NOTHING) { return classMap; } try { BeanInfo beanInfo = Introspector.getBeanInfo(clazz); PropertyDescriptor[] pda = beanInfo.getPropertyDescriptors(); MethodDescriptor[] mda = beanInfo.getMethodDescriptors(); for(int i = pda.length - 1; i >= 0; --i) { populateClassMapWithPropertyDescriptor( pda[i], clazz, accessibleMethods, classMap); } if(exposureLevel < EXPOSE_PROPERTIES_ONLY) { MethodAppearanceDecision decision = new MethodAppearanceDecision(); for(int i = mda.length - 1; i >= 0; --i) { MethodDescriptor md = mda[i]; Method publicMethod = getAccessibleMethod( md.getMethod(), accessibleMethods); if(publicMethod != null && isSafeMethod(publicMethod)) { decision.setDefaults(publicMethod); finetuneMethodAppearance(clazz, publicMethod, decision); PropertyDescriptor propDesc = decision.getExposeAsProperty(); if (propDesc != null && !(classMap.get(propDesc.getName()) instanceof PropertyDescriptor)) { populateClassMapWithPropertyDescriptor( propDesc, clazz, accessibleMethods, classMap); } String methodKey = decision.getExposeMethodAs(); if (methodKey != null) { Object previous = classMap.get(methodKey); if(previous instanceof Method) { // Overloaded method - replace method with a method map MethodMap methodMap = new MethodMap(methodKey, this); methodMap.addMember((Method)previous); methodMap.addMember(publicMethod); classMap.put(methodKey, methodMap); // remove parameter type information getArgTypes(classMap).remove(previous); } else if(previous instanceof MethodMap) { // Already overloaded method - add new overload ((MethodMap)previous).addMember(publicMethod); } else if (decision.getMethodShadowsProperty() || !(previous instanceof PropertyDescriptor)) { // Simple method (this far) classMap.put(methodKey, publicMethod); getArgTypes(classMap).put(publicMethod, publicMethod.getParameterTypes()); } } } } } return classMap; } catch(IntrospectionException e) { logger.warn("Couldn't properly perform introspection for class " + clazz, e); return new HashMap(); } } private void populateClassMapWithPropertyDescriptor(PropertyDescriptor pd, Class clazz, Map accessibleMethods, Map classMap) { if(pd instanceof IndexedPropertyDescriptor) { IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor)pd; Method readMethod = ipd.getIndexedReadMethod(); Method publicReadMethod = getAccessibleMethod(readMethod, accessibleMethods); if(publicReadMethod != null && isSafeMethod(publicReadMethod)) { try { if(readMethod != publicReadMethod) { ipd = new IndexedPropertyDescriptor( ipd.getName(), ipd.getReadMethod(), null, publicReadMethod, null); } classMap.put(ipd.getName(), ipd); getArgTypes(classMap).put(publicReadMethod, publicReadMethod.getParameterTypes()); } catch(IntrospectionException e) { logger.warn("Failed creating a publicly-accessible " + "property descriptor for " + clazz.getName() + " indexed property " + pd.getName() + ", read method " + publicReadMethod, e); } } } else { Method readMethod = pd.getReadMethod(); Method publicReadMethod = getAccessibleMethod(readMethod, accessibleMethods); if(publicReadMethod != null && isSafeMethod(publicReadMethod)) { try { if(readMethod != publicReadMethod) { pd = new PropertyDescriptor(pd.getName(), publicReadMethod, null); pd.setReadMethod(publicReadMethod); } classMap.put(pd.getName(), pd); } catch(IntrospectionException e) { logger.warn("Failed creating a publicly-accessible " + "property descriptor for " + clazz.getName() + " property " + pd.getName() + ", read method " + publicReadMethod, e); } } } } /** * Experimental method; subject to change! * Override this to tweak certain aspects of how methods appear in the * data-model. {@link BeansWrapper} will pass in all Java methods here that * it intends to expose in the data-model as methods (so you can do * obj.foo() in the template). By default this method does nothing. * By overriding it you can do the following tweaks: *
    *
  • Hide a method that would be otherwise shown by calling * {@link MethodAppearanceDecision#setExposeMethodAs(String)} * with null parameter. Note that you can't un-hide methods * that are not public or are considered to by unsafe * (like {@link Object#wait()}) because * {@link #finetuneMethodAppearance} is not called for those.
  • *
  • Show the method with a different name in the data-model than its * real name by calling * {@link MethodAppearanceDecision#setExposeMethodAs(String)} * with non-null parameter. *
  • Create a fake JavaBean property for this method by calling * {@link MethodAppearanceDecision#setExposeAsProperty(PropertyDescriptor)}. * For example, if you have int size() in a class, but you * want it to be accessed from the templates as obj.size, * rather than as obj.size(), you can do that with this. * The default is {@code null}, which means that no fake property is * created for the method. You need not and shouldn't set this * to non-null for the getter methods of real JavaBean * properties, as those are automatically shown as properties anyway. * The property name in the {@link PropertyDescriptor} can be anything, * but the method (or methods) in it must belong to the class that * is given as the clazz parameter or it must be inherited from * that class, or else whatever errors can occur later. * {@link IndexedPropertyDescriptor}-s are supported. * If a real JavaBean property of the same name exists, it won't be * replaced by the fake one. Also if a fake property of the same name * was assigned earlier, it won't be replaced. *
  • Prevent the method to hide a JavaBean property (fake or real) of * the same name by calling * {@link MethodAppearanceDecision#setMethodShadowsProperty(boolean)} * with false. The default is true, so if you have * both a property and a method called "foo", then in the template * myObject.foo will return the method itself instead * of the property value, which is often undesirable. *
* *

Note that you can expose a Java method both as a method and as a * JavaBean property on the same time, however you have to chose different * names for them to prevent shadowing. * * @param decision Stores how the parameter method will be exposed in the * data-model after {@link #finetuneMethodAppearance} returns. * This is initialized so that it reflects the default * behavior of {@link BeansWrapper}. */ protected void finetuneMethodAppearance( Class clazz, Method m, MethodAppearanceDecision decision) { // left everything on its default; do nothing } private static Map getArgTypes(Map classMap) { Map argTypes = (Map)classMap.get(ARGTYPES); if(argTypes == null) { argTypes = new HashMap(); classMap.put(ARGTYPES, argTypes); } return argTypes; } static Class[] getArgTypes(Map classMap, AccessibleObject methodOrCtor) { return (Class[])((Map)classMap.get(ARGTYPES)).get(methodOrCtor); } private static Method getFirstAccessibleMethod(MethodSignature sig, Map accessibles) { List l = (List)accessibles.get(sig); if(l == null || l.isEmpty()) { return null; } return (Method)l.iterator().next(); } private static Method getAccessibleMethod(Method m, Map accessibles) { if(m == null) { return null; } MethodSignature sig = new MethodSignature(m); List l = (List)accessibles.get(sig); if(l == null) { return null; } for (Iterator iterator = l.iterator(); iterator.hasNext();) { Method am = (Method) iterator.next(); if(am.getReturnType() == m.getReturnType()) { return am; } } return null; } boolean isSafeMethod(Method method) { return exposureLevel < EXPOSE_SAFE || !UNSAFE_METHODS.contains(method); } /** * Retrieves mapping of methods to accessible methods for a class. * In case the class is not public, retrieves methods with same * signature as its public methods from public superclasses and * interfaces (if they exist). Basically upcasts every method to the * nearest accessible method. */ private static Map discoverAccessibleMethods(Class clazz) { Map map = new HashMap(); discoverAccessibleMethods(clazz, map); return map; } private static void discoverAccessibleMethods(Class clazz, Map map) { if(Modifier.isPublic(clazz.getModifiers())) { try { Method[] methods = clazz.getMethods(); for(int i = 0; i < methods.length; i++) { Method method = methods[i]; MethodSignature sig = new MethodSignature(method); // Contrary to intuition, a class can actually have several // different methods with same signature *but* different // return types. These can't be constructed using Java the // language, as this is illegal on source code level, but // the compiler can emit synthetic methods as part of // generic type reification that will have same signature // yet different return type than an existing explicitly // declared method. Consider: // public interface I { T m(); } // public class C implements I { Integer m() { return 42; } } // C.class will have both "Object m()" and "Integer m()" methods. List methodList = (List)map.get(sig); if(methodList == null) { methodList = new LinkedList(); map.put(sig, methodList); } methodList.add(method); } return; } catch(SecurityException e) { logger.warn("Could not discover accessible methods of class " + clazz.getName() + ", attemping superclasses/interfaces.", e); // Fall through and attempt to discover superclass/interface // methods } } Class[] interfaces = clazz.getInterfaces(); for(int i = 0; i < interfaces.length; i++) { discoverAccessibleMethods(interfaces[i], map); } Class superclass = clazz.getSuperclass(); if(superclass != null) { discoverAccessibleMethods(superclass, map); } } private static final class MethodSignature { private static final MethodSignature GET_STRING_SIGNATURE = new MethodSignature("get", new Class[] { STRING_CLASS }); private static final MethodSignature GET_OBJECT_SIGNATURE = new MethodSignature("get", new Class[] { OBJECT_CLASS }); private final String name; private final Class[] args; private MethodSignature(String name, Class[] args) { this.name = name; this.args = args; } MethodSignature(Method method) { this(method.getName(), method.getParameterTypes()); } public boolean equals(Object o) { if(o instanceof MethodSignature) { MethodSignature ms = (MethodSignature)o; return ms.name.equals(name) && Arrays.equals(args, ms.args); } return false; } public int hashCode() { return name.hashCode() ^ args.length; } } private static final Set createUnsafeMethodsSet() { Properties props = new Properties(); InputStream in = BeansWrapper.class.getResourceAsStream("unsafeMethods.txt"); if(in != null) { String methodSpec = null; try { try { props.load(in); } finally { in.close(); } Set set = new HashSet(props.size() * 4/3, .75f); Map primClasses = createPrimitiveClassesMap(); for (Iterator iterator = props.keySet().iterator(); iterator.hasNext();) { methodSpec = (String) iterator.next(); try { set.add(parseMethodSpec(methodSpec, primClasses)); } catch(ClassNotFoundException e) { if(DEVELOPMENT) { throw e; } } catch(NoSuchMethodException e) { if(DEVELOPMENT) { throw e; } } } return set; } catch(Exception e) { throw new RuntimeException("Could not load unsafe method " + methodSpec + " " + e.getClass().getName() + " " + e.getMessage()); } } return Collections.EMPTY_SET; } private static Method parseMethodSpec(String methodSpec, Map primClasses) throws ClassNotFoundException, NoSuchMethodException { int brace = methodSpec.indexOf('('); int dot = methodSpec.lastIndexOf('.', brace); Class clazz = ClassUtil.forName(methodSpec.substring(0, dot)); String methodName = methodSpec.substring(dot + 1, brace); String argSpec = methodSpec.substring(brace + 1, methodSpec.length() - 1); StringTokenizer tok = new StringTokenizer(argSpec, ","); int argcount = tok.countTokens(); Class[] argTypes = new Class[argcount]; for (int i = 0; i < argcount; i++) { String argClassName = tok.nextToken(); argTypes[i] = (Class)primClasses.get(argClassName); if(argTypes[i] == null) { argTypes[i] = ClassUtil.forName(argClassName); } } return clazz.getMethod(methodName, argTypes); } private static Map createPrimitiveClassesMap() { Map map = new HashMap(); map.put("boolean", Boolean.TYPE); map.put("byte", Byte.TYPE); map.put("char", Character.TYPE); map.put("short", Short.TYPE); map.put("int", Integer.TYPE); map.put("long", Long.TYPE); map.put("float", Float.TYPE); map.put("double", Double.TYPE); return map; } /** * Converts any {@link BigDecimal}s in the passed array to the type of * the corresponding formal argument of the method. */ public static void coerceBigDecimals(AccessibleObject callable, Object[] args) { Class[] formalTypes = null; for(int i = 0; i < args.length; ++i) { Object arg = args[i]; if(arg instanceof BigDecimal) { if(formalTypes == null) { if(callable instanceof Method) { formalTypes = ((Method)callable).getParameterTypes(); } else if(callable instanceof Constructor) { formalTypes = ((Constructor)callable).getParameterTypes(); } else { throw new IllegalArgumentException("Expected method or " + " constructor; callable is " + callable.getClass().getName()); } } args[i] = coerceBigDecimal((BigDecimal)arg, formalTypes[i]); } } } /** * Converts any {@link BigDecimal}s in the passed array to the type of * the corresponding formal argument of the method. */ public static void coerceBigDecimals(Class[] formalTypes, Object[] args) { int typeLen = formalTypes.length; int argsLen = args.length; int min = Math.min(typeLen, argsLen); for(int i = 0; i < min; ++i) { Object arg = args[i]; if(arg instanceof BigDecimal) { args[i] = coerceBigDecimal((BigDecimal)arg, formalTypes[i]); } } if(argsLen > typeLen) { Class varArgType = formalTypes[typeLen - 1]; for(int i = typeLen; i < argsLen; ++i) { Object arg = args[i]; if(arg instanceof BigDecimal) { args[i] = coerceBigDecimal((BigDecimal)arg, varArgType); } } } } public static Object coerceBigDecimal(BigDecimal bd, Class formalType) { // int is expected in most situations, so we check it first if(formalType == Integer.TYPE || formalType == Integer.class) { return new Integer(bd.intValue()); } else if(formalType == Double.TYPE || formalType == Double.class) { return new Double(bd.doubleValue()); } else if(formalType == Long.TYPE || formalType == Long.class) { return new Long(bd.longValue()); } else if(formalType == Float.TYPE || formalType == Float.class) { return new Float(bd.floatValue()); } else if(formalType == Short.TYPE || formalType == Short.class) { return new Short(bd.shortValue()); } else if(formalType == Byte.TYPE || formalType == Byte.class) { return new Byte(bd.byteValue()); } else if(BIGINTEGER_CLASS.isAssignableFrom(formalType)) { return bd.toBigInteger(); } return bd; } private static ClassBasedModelFactory createEnumModels(BeansWrapper wrapper) { if(ENUMS_MODEL_CTOR != null) { try { return (ClassBasedModelFactory)ENUMS_MODEL_CTOR.newInstance( new Object[] { wrapper }); } catch(Exception e) { throw new UndeclaredThrowableException(e); } } else { return null; } } private static Constructor enumsModelCtor() { try { // Check if Enums are available on this platform Class.forName("java.lang.Enum"); // If they are, return the appropriate constructor for enum models return Class.forName( "freemarker.ext.beans.EnumModels").getDeclaredConstructor( new Class[] { BeansWrapper.class }); } catch(Exception e) { // Otherwise, return null return null; } } private static boolean isJavaRebelAvailable() { try { JavaRebelIntegration.testAvailability(); return true; } catch(NoClassDefFoundError e) { return false; } } /** * Experimental class; subject to change! * Used for {@link #finetuneMethodAppearance} as output parameter; see there. */ static public final class MethodAppearanceDecision { private PropertyDescriptor exposeAsProperty; private String exposeMethodAs; private boolean methodShadowsProperty; void setDefaults(Method m) { exposeAsProperty = null; exposeMethodAs = m.getName(); methodShadowsProperty = true; } public PropertyDescriptor getExposeAsProperty() { return exposeAsProperty; } public void setExposeAsProperty(PropertyDescriptor exposeAsProperty) { this.exposeAsProperty = exposeAsProperty; } public String getExposeMethodAs() { return exposeMethodAs; } public void setExposeMethodAs(String exposeAsMethod) { this.exposeMethodAs = exposeAsMethod; } public boolean getMethodShadowsProperty() { return methodShadowsProperty; } public void setMethodShadowsProperty(boolean shadowEarlierProperty) { this.methodShadowsProperty = shadowEarlierProperty; } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/BeanModel.java0000644000175000017500000003615611723544471025144 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.beans.IndexedPropertyDescriptor; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import freemarker.core.CollectionAndSequence; import freemarker.ext.util.ModelFactory; import freemarker.ext.util.WrapperTemplateModel; import freemarker.log.Logger; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.SimpleScalar; import freemarker.template.SimpleSequence; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateScalarModel; import freemarker.template.utility.StringUtil; /** * A class that will wrap an arbitrary object into {@link freemarker.template.TemplateHashModel} * interface allowing calls to arbitrary property getters and invocation of * accessible methods on the object from a template using the * object.foo to access properties and object.bar(arg1, arg2) to * invoke methods on it. You can also use the object.foo[index] syntax to * access indexed properties. It uses Beans {@link java.beans.Introspector} * to dynamically discover the properties and methods. * @author Attila Szegedi * @version $Id: BeanModel.java,v 1.49.2.4 2006/11/12 10:20:37 szegedia Exp $ */ public class BeanModel implements TemplateHashModelEx, AdapterTemplateModel, WrapperTemplateModel { private static final Logger logger = Logger.getLogger("freemarker.beans"); protected final Object object; protected final BeansWrapper wrapper; // We use this to represent an unknown value as opposed to known value of null (JR) static final TemplateModel UNKNOWN = new SimpleScalar("UNKNOWN"); static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new BeanModel(object, (BeansWrapper)wrapper); } }; // Cached template models that implement member properties and methods for this // instance. Keys are FeatureDescriptor instances (from classCache values), // values are either ReflectionMethodModels/ReflectionScalarModels private HashMap memberMap; /** * Creates a new model that wraps the specified object. Note that there are * specialized subclasses of this class for wrapping arrays, collections, * enumeration, iterators, and maps. Note also that the superclass can be * used to wrap String objects if only scalar functionality is needed. You * can also choose to delegate the choice over which model class is used for * wrapping to {@link BeansWrapper#wrap(Object)}. * @param object the object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public BeanModel(Object object, BeansWrapper wrapper) { this.object = object; this.wrapper = wrapper; if (object == null) { return; } wrapper.introspectClass(object.getClass()); } /** * Uses Beans introspection to locate a property or method with name * matching the key name. If a method or property is found, it is wrapped * into {@link freemarker.template.TemplateMethodModelEx} (for a method or * indexed property), or evaluated on-the-fly and the return value wrapped * into appropriate model (for a simple property) Models for various * properties and methods are cached on a per-class basis, so the costly * introspection is performed only once per property or method of a class. * (Side-note: this also implies that any class whose method has been called * will be strongly referred to by the framework and will not become * unloadable until this class has been unloaded first. Normally this is not * an issue, but can be in a rare scenario where you create many classes on- * the-fly. Also, as the cache grows with new classes and methods introduced * to the framework, it may appear as if it were leaking memory. The * framework does, however detect class reloads (if you happen to be in an * environment that does this kind of things--servlet containers do it when * they reload a web application) and flushes the cache. If no method or * property matching the key is found, the framework will try to invoke * methods with signature * non-void-return-type get(java.lang.String), * then non-void-return-type get(java.lang.Object), or * alternatively (if the wrapped object is a resource bundle) * Object getObject(java.lang.String). * @throws TemplateModelException if there was no property nor method nor * a generic get method to invoke. */ public TemplateModel get(String key) throws TemplateModelException { Class clazz = object.getClass(); Map classInfo = wrapper.getClassKeyMap(clazz); TemplateModel retval = null; try { if(wrapper.isMethodsShadowItems()) { Object fd = classInfo.get(key); if(fd != null) { retval = invokeThroughDescriptor(fd, classInfo); } else { retval = invokeGenericGet(classInfo, clazz, key); } } else { TemplateModel model = invokeGenericGet(classInfo, clazz, key); final TemplateModel nullModel = wrapper.wrap(null); if(model != nullModel && model != UNKNOWN) { return model; } Object fd = classInfo.get(key); if(fd != null) { retval = invokeThroughDescriptor(fd, classInfo); if (retval == UNKNOWN && model == nullModel) { // This is the (somewhat subtle) case where the generic get() returns null // and we have no bean info, so we respect the fact that // the generic get() returns null and return null. (JR) retval = nullModel; } } } if (retval == UNKNOWN) { if (wrapper.isStrict()) { throw new InvalidPropertyException("No such bean property: " + key); } else if (logger.isDebugEnabled()) { logNoSuchKey(key, classInfo); } retval = wrapper.wrap(null); } return retval; } catch(TemplateModelException e) { throw e; } catch(Exception e) { throw new TemplateModelException("get(" + key + ") failed on " + "instance of " + object.getClass().getName(), e); } } private void logNoSuchKey(String key, Map keyMap) { logger.debug("Key " + StringUtil.jQuoteNoXSS(key) + " was not found on instance of " + object.getClass().getName() + ". Introspection information for " + "the class is: " + keyMap); } /** * Whether the model has a plain get(String) or get(Object) method */ protected boolean hasPlainGetMethod() { return wrapper.getClassKeyMap(object.getClass()).get(BeansWrapper.GENERIC_GET_KEY) != null; } private TemplateModel invokeThroughDescriptor(Object desc, Map classInfo) throws IllegalAccessException, InvocationTargetException, TemplateModelException { // See if this particular instance has a cached implementation // for the requested feature descriptor TemplateModel member; synchronized(this) { if(memberMap != null) { member = (TemplateModel)memberMap.get(desc); } else { member = null; } } if(member != null) return member; TemplateModel retval = UNKNOWN; if(desc instanceof IndexedPropertyDescriptor) { Method readMethod = ((IndexedPropertyDescriptor)desc).getIndexedReadMethod(); retval = member = new SimpleMethodModel(object, readMethod, BeansWrapper.getArgTypes(classInfo, readMethod), wrapper); } else if(desc instanceof PropertyDescriptor) { PropertyDescriptor pd = (PropertyDescriptor)desc; retval = wrapper.invokeMethod(object, pd.getReadMethod(), null); // (member == null) condition remains, as we don't cache these } else if(desc instanceof Field) { retval = wrapper.wrap(((Field)desc).get(object)); // (member == null) condition remains, as we don't cache these } else if(desc instanceof Method) { Method method = (Method)desc; retval = member = new SimpleMethodModel(object, method, BeansWrapper.getArgTypes(classInfo, method), wrapper); } else if(desc instanceof MethodMap) { retval = member = new OverloadedMethodModel(object, (MethodMap)desc); } // If new cacheable member was created, cache it if(member != null) { synchronized(this) { if(memberMap == null) { memberMap = new HashMap(); } memberMap.put(desc, member); } } return retval; } protected TemplateModel invokeGenericGet(Map keyMap, Class clazz, String key) throws IllegalAccessException, InvocationTargetException, TemplateModelException { Method genericGet = (Method)keyMap.get(BeansWrapper.GENERIC_GET_KEY); if(genericGet == null) return UNKNOWN; return wrapper.invokeMethod(object, genericGet, new Object[] { key }); } protected TemplateModel wrap(Object obj) throws TemplateModelException { return wrapper.getOuterIdentity().wrap(obj); } protected Object unwrap(TemplateModel model) throws TemplateModelException { return wrapper.unwrap(model); } /** * Tells whether the model is empty. It is empty if either the wrapped * object is null, or it is a Boolean with false value. */ public boolean isEmpty() { if (object instanceof String) { return ((String) object).length() == 0; } if (object instanceof Collection) { return ((Collection) object).isEmpty(); } if (object instanceof Map) { return ((Map) object).isEmpty(); } return object == null || Boolean.FALSE.equals(object); } public Object getAdaptedObject(Class hint) { return object; } public Object getWrappedObject() { return object; } public int size() { return wrapper.keyCount(object.getClass()); } public TemplateCollectionModel keys() { return new CollectionAndSequence(new SimpleSequence(keySet(), wrapper)); } public TemplateCollectionModel values() throws TemplateModelException { List values = new ArrayList(size()); TemplateModelIterator it = keys().iterator(); while (it.hasNext()) { String key = ((TemplateScalarModel)it.next()).getAsString(); values.add(get(key)); } return new CollectionAndSequence(new SimpleSequence(values, wrapper)); } public String toString() { return object.toString(); } /** * Helper method to support TemplateHashModelEx. Returns the Set of * Strings which are available via the TemplateHashModel * interface. Subclasses that override invokeGenericGet to * provide additional hash keys should also override this method. */ protected Set keySet() { return wrapper.keySet(object.getClass()); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/CollectionModel.java0000644000175000017500000001336211723544470026363 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.Collection; import java.util.List; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateSequenceModel; /** *

A special case of {@link BeanModel} that can wrap Java collections * and that implements the {@link TemplateCollectionModel} in order to be usable * in a <foreach> block.

* @author Attila Szegedi * @version $Id: CollectionModel.java,v 1.22 2003/06/03 13:21:32 szegedia Exp $ */ public class CollectionModel extends StringModel implements TemplateCollectionModel, TemplateSequenceModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new CollectionModel((Collection)object, (BeansWrapper)wrapper); } }; /** * Creates a new model that wraps the specified collection object. * @param collection the collection object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public CollectionModel(Collection collection, BeansWrapper wrapper) { super(collection, wrapper); } /** * Retrieves the i-th object from the collection, wrapped as a TemplateModel. * @throws TemplateModelException if the index is out of bounds, or the * underlying collection is not a List. */ public TemplateModel get(int index) throws TemplateModelException { // Don't forget to keep getSupportsIndexedAccess in sync with this! if (object instanceof List) { try { return wrap(((List)object).get(index)); } catch(IndexOutOfBoundsException e) { return null; // throw new TemplateModelException("Index out of bounds: " + index); } } else { throw new TemplateModelException("Underlying collection is not a list, it's " + object.getClass().getName()); } } /** * Tells if {@link #get(int)} will always fail for this object. * As this object implements {@link TemplateSequenceModel}, * {@link #get(int)} should always work, but due to a design flaw, for * non-{@link List} wrapped objects {@link #get(int)} will always fail. * This method exists to ease working this problem around. */ public boolean getSupportsIndexedAccess() { return object instanceof List; } public TemplateModelIterator iterator() { return new IteratorModel(((Collection)object).iterator(), wrapper); } public int size() { return ((Collection)object).size(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/SimpleMemberModel.java0000644000175000017500000002034511723544470026650 0ustar ebourgebourg/* * Copyright (c) 2003-2007 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Array; import java.lang.reflect.Member; import java.util.Collections; import java.util.Iterator; import java.util.List; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.StringUtil; /** * This class is used for constructors and as a base for non-overloaded methods * @author Attila Szegedi * @version $Id: $ */ class SimpleMemberModel { private final Member member; private final Class[] argTypes; protected SimpleMemberModel(Member member, Class[] argTypes) { this.member = member; this.argTypes = argTypes; } Object[] unwrapArguments(List arguments, BeansWrapper wrapper) throws TemplateModelException { if(arguments == null) { arguments = Collections.EMPTY_LIST; } boolean isVarArg = MethodUtilities.isVarArgs(member); int typesLen = argTypes.length; if(isVarArg) { if(typesLen - 1 > arguments.size()) { throw new TemplateModelException("Method " + member + " takes at least " + (typesLen - 1) + " arguments, " + arguments.size() + " was given."); } } else if(typesLen != arguments.size()) { throw new TemplateModelException("Method " + member + " takes exactly " + typesLen + " arguments, " + arguments.size() + " was given."); } Object[] args = unwrapArguments(arguments, argTypes, isVarArg, wrapper); return args; } static Object[] unwrapArguments(List args, Class[] argTypes, boolean isVarargs, BeansWrapper w) throws TemplateModelException { if(args == null) return null; int typesLen = argTypes.length; int argsLen = args.size(); Object[] unwrappedArgs = new Object[typesLen]; // Unwrap arguments: Iterator it = args.iterator(); int normalArgCnt = isVarargs ? typesLen - 1 : typesLen; int argIdx = 0; while (argIdx < normalArgCnt) { Class argType = argTypes[argIdx]; TemplateModel argVal = (TemplateModel) it.next(); Object unwrappedArgVal = w.unwrapInternal(argVal, argType); if(unwrappedArgVal == BeansWrapper.CAN_NOT_UNWRAP) { throw createArgumentTypeMismarchException(argIdx, argVal, argType); } unwrappedArgs[argIdx++] = unwrappedArgVal; } if (isVarargs) { // The last argType, which is the vararg type, wasn't processed yet. Class varargType = argTypes[typesLen - 1]; Class varargItemType = varargType.getComponentType(); if (!it.hasNext()) { unwrappedArgs[argIdx++] = Array.newInstance(varargItemType, 0); } else { TemplateModel argVal = (TemplateModel) it.next(); Object unwrappedArgVal; // We first try to treat the last argument as a vararg *array*. // This is consistent to what OverloadedVarArgMethod does. if (argsLen - argIdx == 1 && (unwrappedArgVal = w.unwrapInternal(argVal, varargType)) != BeansWrapper.CAN_NOT_UNWRAP) { // It was a vararg array. unwrappedArgs[argIdx++] = unwrappedArgVal; } else { // It wasn't a vararg array, so we assume it's a vararg // array *item*, possibly followed by further ones. int varargArrayLen = argsLen - argIdx; Object varargArray = Array.newInstance(varargItemType, varargArrayLen); for (int varargIdx = 0; varargIdx < varargArrayLen; varargIdx++) { TemplateModel varargVal = (TemplateModel) (varargIdx == 0 ? argVal : it.next()); Object unwrappedVarargVal = w.unwrapInternal(varargVal, varargItemType); if(unwrappedVarargVal == BeansWrapper.CAN_NOT_UNWRAP) { throw createArgumentTypeMismarchException( argIdx + varargIdx, varargVal, varargItemType); } if (unwrappedVarargVal == null && varargItemType.isPrimitive()) { throw createArgumentTypeMismarchException( argIdx + varargIdx, unwrappedVarargVal, varargItemType); } Array.set(varargArray, varargIdx, unwrappedVarargVal); } unwrappedArgs[argIdx++] = varargArray; } } } return unwrappedArgs; } private static TemplateModelException createArgumentTypeMismarchException( int argIdx, Object argVal, Class targetType) { return new TemplateModelException( "Argument type mismatch; can not unwrap argument #" + (argIdx + 1) + " (" + (argVal == null ? "value: null" : "class: " + argVal.getClass().getName() + ", toString: " + StringUtil.jQuote(argVal)) + ") to " + targetType); } protected Member getMember() { return member; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/OverloadedVarArgMethod.java0000644000175000017500000002427111723544471027641 0ustar ebourgebourg/* * Copyright (c) 2003-2007 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Array; import java.lang.reflect.Member; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * @author Attila Szegedi * @version $Id: $ */ class OverloadedVarArgMethod extends OverloadedMethod { private static final Map canoncialArgPackers = new HashMap(); private final Map argPackers = new HashMap(); private static class ArgumentPacker { private final int argCount; private final Class varArgType; ArgumentPacker(Class[] argTypes) { argCount = argTypes.length; varArgType = argTypes[argCount - 1].getComponentType(); } Object[] packArgs(Object[] args, List modelArgs, BeansWrapper w) throws TemplateModelException { final int actualArgCount = args.length; final int fixArgCount = argCount - 1; if(args.length != argCount) { Object[] newargs = new Object[argCount]; System.arraycopy(args, 0, newargs, 0, fixArgCount); Object array = Array.newInstance(varArgType, actualArgCount - fixArgCount); for(int i = fixArgCount; i < actualArgCount; ++i) { Object val = w.unwrapInternal((TemplateModel)modelArgs.get(i), varArgType); if(val == BeansWrapper.CAN_NOT_UNWRAP) { return null; } Array.set(array, i - fixArgCount, val); } newargs[fixArgCount] = array; return newargs; } else { Object val = w.unwrapInternal((TemplateModel)modelArgs.get(fixArgCount), varArgType); if(val == BeansWrapper.CAN_NOT_UNWRAP) { return null; } Object array = Array.newInstance(varArgType, 1); Array.set(array, 0, val); args[fixArgCount] = array; return args; } } public boolean equals(Object obj) { if(obj instanceof ArgumentPacker) { ArgumentPacker p = (ArgumentPacker)obj; return argCount == p.argCount && varArgType == p.varArgType; } return false; } public int hashCode() { return argCount ^ varArgType.hashCode(); } } void onAddSignature(Member member, Class[] argTypes) { ArgumentPacker argPacker = new ArgumentPacker(argTypes); synchronized(canoncialArgPackers) { ArgumentPacker canonical = (ArgumentPacker) canoncialArgPackers.get(argPacker); if(canonical == null) { canoncialArgPackers.put(argPacker, argPacker); } else { argPacker = canonical; } } argPackers.put(member, argPacker); componentizeLastType(argTypes); } void updateSignature(int l) { Class[][] marshalTypes = getMarshalTypes(); Class[] newTypes = marshalTypes[l]; // First vararg marshal type spec with less parameters than the // current spec influences the types of the current marshal spec. for(int i = l; i-->0;) { Class[] previousTypes = marshalTypes[i]; if(previousTypes != null) { varArgUpdate(newTypes, previousTypes); break; } } // Vararg marshal spec with exactly one parameter more than the current // spec influences the types of the current spec if(l + 1 < marshalTypes.length) { Class[] oneLongerTypes = marshalTypes[l + 1]; if(oneLongerTypes != null) { varArgUpdate(newTypes, oneLongerTypes); } } } void afterSignatureAdded(int l) { // Since this member is vararg, its types influence the types in all // type specs longer than itself. Class[][] marshalTypes = getMarshalTypes(); Class[] newTypes = marshalTypes[l]; for(int i = l + 1; i < marshalTypes.length; ++i) { Class[] existingTypes = marshalTypes[i]; if(existingTypes != null) { varArgUpdate(existingTypes, newTypes); } } // It also influences the types in the marshal spec that is exactly // one argument shorter (as vararg methods can be invoked with 0 // variable arguments, that is, with k-1 cardinality). if(l > 0) { Class[] oneShorterTypes = marshalTypes[l - 1]; if(oneShorterTypes != null) { varArgUpdate(oneShorterTypes, newTypes); } } } private static void varArgUpdate(Class[] modifiedTypes, Class[] modifyingTypes) { final int dl = modifiedTypes.length; final int gl = modifyingTypes.length; int min = Math.min(gl, dl); for(int i = 0; i < min; ++i) { modifiedTypes[i] = MethodUtilities.getMostSpecificCommonType(modifiedTypes[i], modifyingTypes[i]); } if(dl > gl) { Class varArgType = modifyingTypes[gl - 1]; for(int i = gl; i < dl; ++i) { modifiedTypes[i] = MethodUtilities.getMostSpecificCommonType(modifiedTypes[i], varArgType); } } } private static void componentizeLastType(Class[] types) { int l1 = types.length - 1; //assert l1 >= 0; //assert types[l1].isArray(); types[l1] = types[l1].getComponentType(); } Object getMemberAndArguments(List arguments, BeansWrapper w) throws TemplateModelException { if(arguments == null) { // null is treated as empty args arguments = Collections.EMPTY_LIST; } int l = arguments.size(); Class[][] marshalTypes = getMarshalTypes(); Object[] args = new Object[l]; // Starting from args.length + 1 as we must try to match against a case // where all specified args are fixargs, and the vararg portion // contains zero args outer: for(int j = Math.min(l + 1, marshalTypes.length - 1); j >= 0; --j) { Class[] types = marshalTypes[j]; if(types == null) { if(j == 0) { return NO_SUCH_METHOD; } continue; } // Try to marshal the arguments Iterator it = arguments.iterator(); for(int i = 0; i < l; ++i) { Object dst = w.unwrapInternal((TemplateModel)it.next(), i < j ? types[i] : types[j - 1]); if(dst == BeansWrapper.CAN_NOT_UNWRAP) { continue outer; } if(dst != args[i]) { args[i] = dst; } } break; } Object objMember = getMemberForArgs(args, true); if(objMember instanceof Member) { Member member = (Member)objMember; args = ((ArgumentPacker)argPackers.get(member)).packArgs(args, arguments, w); if(args == null) { return NO_SUCH_METHOD; } BeansWrapper.coerceBigDecimals(getSignature(member), args); return new MemberAndArguments(member, args); } return objMember; // either NOT_FOUND or AMBIGUOUS } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/StringModel.java0000644000175000017500000001014611723544470025533 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateScalarModel; /** * Subclass of {@link BeanModel} that exposes the return value of the {@link * java.lang.Object#toString()} method through the {@link TemplateScalarModel} * interface. * @author Attila Szegedi * @version $Id: StringModel.java,v 1.9 2003/06/03 13:21:33 szegedia Exp $ */ public class StringModel extends BeanModel implements TemplateScalarModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new StringModel(object, (BeansWrapper)wrapper); } }; /** * Creates a new model that wraps the specified object with BeanModel + scalar * functionality. * @param object the object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public StringModel(Object object, BeansWrapper wrapper) { super(object, wrapper); } /** * Returns the result of calling {@link Object#toString()} on the wrapped * object. */ public String getAsString() { return object.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/NumberModel.java0000644000175000017500000000762611723544471025527 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateNumberModel; /** * Wraps arbitrary subclass of {@link java.lang.Number} into a reflective model. * Beside acting as a {@link TemplateNumberModel}, you can call all Java methods on * these objects as well. */ public class NumberModel extends BeanModel implements TemplateNumberModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new NumberModel((Number)object, (BeansWrapper)wrapper); } }; /** * Creates a new model that wraps the specified number object. * @param number the number object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public NumberModel(Number number, BeansWrapper wrapper) { super(number, wrapper); } public Number getAsNumber() { return (Number)object; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/ClassString.java0000644000175000017500000002767011723544470025552 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Member; import java.math.BigDecimal; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * * @author Attila Szegedi * @version $Id: $ * @param */ final class ClassString { private static final Class BIGDECIMAL_CLASS = BigDecimal.class; private static final Class NUMBER_CLASS = Number.class; private final Class[] classes; ClassString(Object[] objects) { int l = objects.length; classes = new Class[l]; for(int i = 0; i < l; ++i) { Object obj = objects[i]; classes[i] = obj == null ? MethodUtilities.OBJECT_CLASS : obj.getClass(); } } Class[] getClasses() { return classes; } public int hashCode() { int hash = 0; for(int i = 0; i < classes.length; ++i) { hash ^= classes[i].hashCode(); } return hash; } public boolean equals(Object o) { if(o instanceof ClassString) { ClassString cs = (ClassString)o; if(cs.classes.length != classes.length) { return false; } for(int i = 0; i < classes.length; ++i) { if(cs.classes[i] != classes[i]) { return false; } } return true; } return false; } private static final int MORE_SPECIFIC = 0; private static final int LESS_SPECIFIC = 1; private static final int INDETERMINATE = 2; Object getMostSpecific(List methods, boolean varArg) { LinkedList applicables = getApplicables(methods, varArg); if(applicables.isEmpty()) { return OverloadedMethod.NO_SUCH_METHOD; } if(applicables.size() == 1) { return applicables.getFirst(); } LinkedList maximals = new LinkedList(); for (Iterator it = applicables.iterator(); it.hasNext();) { Member applicable = (Member)it.next(); Class[] appArgs = MethodUtilities.getParameterTypes(applicable); boolean lessSpecific = false; for (Iterator maximal = maximals.iterator(); maximal.hasNext();) { Member max = (Member)maximal.next(); Class[] maxArgs = MethodUtilities.getParameterTypes(max); switch(moreSpecific(appArgs, maxArgs, varArg)) { case MORE_SPECIFIC: { maximal.remove(); break; } case LESS_SPECIFIC: { lessSpecific = true; break; } } } if(!lessSpecific) { maximals.addLast(applicable); } } if(maximals.size() > 1) { return OverloadedMethod.AMBIGUOUS_METHOD; } return maximals.getFirst(); } private static int moreSpecific(Class[] c1, Class[] c2, boolean varArg) { boolean c1MoreSpecific = false; boolean c2MoreSpecific = false; final int cl1 = c1.length; final int cl2 = c2.length; //assert varArg || cl1 == cl2; for(int i = 0; i < cl1; ++i) { Class class1 = getClass(c1, cl1, i, varArg); Class class2 = getClass(c2, cl2, i, varArg); if(class1 != class2) { c1MoreSpecific = c1MoreSpecific || MethodUtilities.isMoreSpecific(class1, class2); c2MoreSpecific = c2MoreSpecific || MethodUtilities.isMoreSpecific(class2, class1); } } if(c1MoreSpecific) { if(c2MoreSpecific) { return INDETERMINATE; } return MORE_SPECIFIC; } if(c2MoreSpecific) { return LESS_SPECIFIC; } return INDETERMINATE; } private static Class getClass(Class[] classes, int l, int i, boolean varArg) { return varArg && i >= l - 1 ? classes[l - 1].getComponentType() : classes[i]; } /** * Returns all methods that are applicable to actual * parameter classes represented by this ClassString object. */ LinkedList getApplicables(List methods, boolean varArg) { LinkedList list = new LinkedList(); for (Iterator it = methods.iterator(); it.hasNext();) { Member member = (Member)it.next(); if(isApplicable(member, varArg)) { list.add(member); } } return list; } /** * Returns true if the supplied method is applicable to actual * parameter classes represented by this ClassString object. * */ private boolean isApplicable(Member member, boolean varArg) { final Class[] formalTypes = MethodUtilities.getParameterTypes(member); final int cl = classes.length; final int fl = formalTypes.length - (varArg ? 1 : 0); if(varArg) { if(cl < fl) { return false; } } else { if(cl != fl) { return false; } } for(int i = 0; i < fl; ++i) { if(!isMethodInvocationConvertible(formalTypes[i], classes[i])) { return false; } } if(varArg) { Class varArgType = formalTypes[fl].getComponentType(); for(int i = fl; i < cl; ++i) { if(!isMethodInvocationConvertible(varArgType, classes[i])) { return false; } } } return true; } /** * Determines whether a type represented by a class object is * convertible to another type represented by a class object using a * method invocation conversion, treating object types of primitive * types as if they were primitive types (that is, a Boolean actual * parameter type matches boolean primitive formal type). This behavior * is because this method is used to determine applicable methods for * an actual parameter list, and primitive types are represented by * their object duals in reflective method calls. * @param formal the formal parameter type to which the actual * parameter type should be convertible * @param actual the actual parameter type. * @return true if either formal type is assignable from actual type, * or formal is a primitive type and actual is its corresponding object * type or an object type of a primitive type that can be converted to * the formal type. */ static boolean isMethodInvocationConvertible(Class formal, Class actual) { // Check for identity or widening reference conversion if(formal.isAssignableFrom(actual)) { return true; } // Check for boxing with widening primitive conversion. Note that // actual parameters are never primitives. if(formal.isPrimitive()) { if(formal == Boolean.TYPE) return actual == Boolean.class; if(formal == Character.TYPE) return actual == Character.class; if(formal == Byte.TYPE && actual == Byte.class) return true; if(formal == Short.TYPE && (actual == Short.class || actual == Byte.class)) return true; if(formal == Integer.TYPE && (actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; if(formal == Long.TYPE && (actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; if(formal == Float.TYPE && (actual == Float.class || actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; if(formal == Double.TYPE && (actual == Double.class || actual == Float.class || actual == Long.class || actual == Integer.class || actual == Short.class || actual == Byte.class)) return true; // Special case for BigDecimals as we deem BigDecimal to be // convertible to any numeric type - either object or primitive. // This can actually cause us trouble as this is a narrowing // conversion, not widening. return isBigDecimalConvertible(formal, actual); } return false; } private static boolean isBigDecimalConvertible(Class formal, Class actual) { // BigDecimal if(BIGDECIMAL_CLASS.isAssignableFrom(actual)) { if(NUMBER_CLASS.isAssignableFrom(formal)) { return true; } if(formal.isPrimitive() && formal != Boolean.TYPE && formal != Character.TYPE) { return true; } } return false; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/SimpleMapModel.java0000644000175000017500000001314611723544467026165 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.List; import java.util.Map; import freemarker.core.CollectionAndSequence; import freemarker.ext.util.ModelFactory; import freemarker.ext.util.WrapperTemplateModel; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.SimpleSequence; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.WrappingTemplateModel; /** * Model used by {@link BeansWrapper} when simpleMapWrapper * mode is enabled. Provides a simple hash model interface to the * underlying map (does not copy like {@link freemarker.template.SimpleHash}), * and a method interface to non-string keys. * @author Chris Nokleberg * @version $Id: SimpleMapModel.java,v 1.9 2005/06/12 19:03:04 szegedia Exp $ */ public class SimpleMapModel extends WrappingTemplateModel implements TemplateHashModelEx, TemplateMethodModelEx, AdapterTemplateModel, WrapperTemplateModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new SimpleMapModel((Map)object, (BeansWrapper)wrapper); } }; private final Map map; public SimpleMapModel(Map map, BeansWrapper wrapper) { super(wrapper); this.map = map; } public TemplateModel get(String key) throws TemplateModelException { Object val = map.get(key); if(val == null) { if(key.length() == 1) { // just check for Character key if this is a single-character string Character charKey = new Character(key.charAt(0)); val = map.get(charKey); if (val == null && !(map.containsKey(key) || map.containsKey(charKey))) { return null; } } else if(!map.containsKey(key)) { return null; } } return wrap(val); } public Object exec(List args) throws TemplateModelException { Object key = ((BeansWrapper)getObjectWrapper()).unwrap((TemplateModel)args.get(0)); Object value = map.get(key); if (value == null && !map.containsKey(key)) { return null; } return wrap(value); } public boolean isEmpty() { return map.isEmpty(); } public int size() { return map.size(); } public TemplateCollectionModel keys() { return new CollectionAndSequence(new SimpleSequence(map.keySet(), getObjectWrapper())); } public TemplateCollectionModel values() { return new CollectionAndSequence(new SimpleSequence(map.values(), getObjectWrapper())); } public Object getAdaptedObject(Class hint) { return map; } public Object getWrappedObject() { return map; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/ClassBasedModelFactory.java0000644000175000017500000001075611723544470027630 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.HashMap; import java.util.Map; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.ClassUtil; /** * Base class for hash models keyed by Java class names. * @author Attila Szegedi * @version $Id: ClassBasedModelFactory.java,v 1.1.2.2 2006/11/12 10:23:02 szegedia Exp $ */ abstract class ClassBasedModelFactory implements TemplateHashModel { private final BeansWrapper wrapper; private final Map cache = new HashMap(); protected ClassBasedModelFactory(BeansWrapper wrapper) { this.wrapper = wrapper; } public TemplateModel get(String key) throws TemplateModelException { synchronized(cache) { TemplateModel model = (TemplateModel)cache.get(key); if(model == null) { try { Class clazz = ClassUtil.forName(key); model = createModel(clazz); // This is called so that we trigger the // class-reloading detector. If there was a class reload, // the wrapper will in turn call our clearCache method. wrapper.introspectClass(clazz); } catch(Exception e) { throw new TemplateModelException(e); } cache.put(key, model); } return model; } } void clearCache() { synchronized(cache) { cache.clear(); } } void removeIntrospectionInfo(Class clazz) { synchronized(cache) { cache.remove(clazz.getName()); } } public boolean isEmpty() { return false; } protected abstract TemplateModel createModel(Class clazz) throws TemplateModelException; protected BeansWrapper getWrapper() { return wrapper; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/SequenceAdapter.java0000644000175000017500000000234411723544467026364 0ustar ebourgebourgpackage freemarker.ext.beans; import java.util.AbstractList; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelAdapter; import freemarker.template.TemplateModelException; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: SequenceAdapter.java,v 1.2 2005/06/12 19:03:04 szegedia Exp $ */ class SequenceAdapter extends AbstractList implements TemplateModelAdapter { private final BeansWrapper wrapper; private final TemplateSequenceModel model; SequenceAdapter(TemplateSequenceModel model, BeansWrapper wrapper) { this.model = model; this.wrapper = wrapper; } public TemplateModel getTemplateModel() { return model; } public int size() { try { return model.size(); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public Object get(int index) { try { return wrapper.unwrap(model.get(index)); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/BooleanModel.java0000644000175000017500000000622111723544471025644 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import freemarker.template.TemplateBooleanModel; /** *

A class that will wrap instances of {@link java.lang.Boolean} into a * {@link TemplateBooleanModel}. * @author Attila Szegedi * @version $Id: BooleanModel.java,v 1.8 2003/01/12 23:40:12 revusky Exp $ */ public class BooleanModel extends BeanModel implements TemplateBooleanModel { private final boolean value; public BooleanModel(Boolean bool, BeansWrapper wrapper) { super(bool, wrapper); value = bool.booleanValue(); } public boolean getAsBoolean() { return value; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/SetAdapter.java0000644000175000017500000000060411723544470025336 0ustar ebourgebourgpackage freemarker.ext.beans; import java.util.Set; import freemarker.template.TemplateCollectionModel; /** * @author Attila Szegedi * @version $Id: SetAdapter.java,v 1.1.2.1 2006/12/22 13:47:36 szegedia Exp $ */ class SetAdapter extends CollectionAdapter implements Set { SetAdapter(TemplateCollectionModel model, BeansWrapper wrapper) { super(model, wrapper); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/IteratorModel.java0000644000175000017500000001315611723544472026064 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.Iterator; import java.util.NoSuchElementException; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; /** *

A class that adds {@link TemplateModelIterator} functionality to the * {@link Iterator} interface implementers. *

*

It differs from the {@link freemarker.template.SimpleCollection} in that * it inherits from {@link BeanModel}, and therefore you can call methods on * it directly, even to the effect of calling iterator.remove() in * the template.

Using the model as a collection model is NOT * thread-safe, as iterators are inherently not thread-safe. * Further, you can iterate over it only once. Attempts to call the * {@link #iterator()} method after it was already driven to the end once will * throw an exception.

* @author Attila Szegedi * @version $Id: IteratorModel.java,v 1.26 2003/06/03 13:21:32 szegedia Exp $ */ public class IteratorModel extends BeanModel implements TemplateModelIterator, TemplateCollectionModel { private boolean accessed = false; /** * Creates a new model that wraps the specified iterator object. * @param iterator the iterator object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public IteratorModel(Iterator iterator, BeansWrapper wrapper) { super(iterator, wrapper); } /** * This allows the iterator to be used in a <foreach> block. * @return "this" */ public TemplateModelIterator iterator() throws TemplateModelException { synchronized(this) { if(accessed) { throw new TemplateModelException( "This collection is stateful and can not be iterated over the" + " second time."); } accessed = true; } return this; } /** * Calls underlying {@link Iterator#hasNext()}. */ public boolean hasNext() { return ((Iterator)object).hasNext(); } /** * Calls underlying {@link Iterator#next()} and wraps the result. */ public TemplateModel next() throws TemplateModelException { try { return wrap(((Iterator)object).next()); } catch(NoSuchElementException e) { throw new TemplateModelException( "No more elements in the iterator.", e); } } /** * Returns {@link Iterator#hasNext()}. Therefore, an * iterator that has no more element evaluates to false, and an * iterator that has further elements evaluates to true. */ public boolean getAsBoolean() { return hasNext(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/MapModel.java0000644000175000017500000001412711723544471025006 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.List; import java.util.Map; import java.util.Set; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** *

A special case of {@link BeanModel} that adds implementation * for {@link TemplateMethodModelEx} on map objects that is a shortcut for the * Map.get() method. Note that if the passed argument itself is a * reflection-wrapper model, then the map lookup will be performed using the * wrapped object as the key. Note that you can call get() using the * map.key syntax inherited from {@link BeanModel} as well, * however in that case the key is always a string.

*

The class itself does not implement the {@link freemarker.template.TemplateCollectionModel}. * You can, however use map.entrySet(), map.keySet(), or * map.values() to obtain {@link freemarker.template.TemplateCollectionModel} instances for * various aspects of the map.

* @author Attila Szegedi * @version $Id: MapModel.java,v 1.26.2.3 2006/02/26 18:26:37 revusky Exp $ */ public class MapModel extends StringModel implements TemplateMethodModelEx { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new MapModel((Map)object, (BeansWrapper)wrapper); } }; /** * Creates a new model that wraps the specified map object. * @param map the map object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public MapModel(Map map, BeansWrapper wrapper) { super(map, wrapper); } /** * The first argument is used as a key to call the map's get method. */ public Object exec(List arguments) throws TemplateModelException { Object key = unwrap((TemplateModel)arguments.get(0)); return wrap(((Map)object).get(key)); } /** * Overridden to invoke the generic get method by casting to Map instead of * through reflection - should yield better performance. */ protected TemplateModel invokeGenericGet(Map keyMap, Class clazz, String key) throws TemplateModelException { Map map = (Map) object; Object val = map.get(key); if(val == null) { if(key.length() == 1) { // just check for Character key if this is a single-character string Character charKey = new Character(key.charAt(0)); val = map.get(charKey); if (val == null && !(map.containsKey(key) || map.containsKey(charKey))) { return UNKNOWN; } } else if(!map.containsKey(key)) { return UNKNOWN; } } return wrap(val); } public boolean isEmpty() { return ((Map)object).isEmpty() && super.isEmpty(); } public int size() { return keySet().size(); } protected Set keySet() { Set set = super.keySet(); set.addAll(((Map)object).keySet()); return set; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/EnumModels.java0000644000175000017500000000710311723544470025353 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.LinkedHashMap; import java.util.Map; import freemarker.template.TemplateModel; /** * @author Attila Szegedi * @version $Id: EnumModels.java,v 1.1.2.3 2007/02/08 14:53:27 szegedia Exp $ */ class EnumModels extends ClassBasedModelFactory { EnumModels(BeansWrapper wrapper) { super(wrapper); } protected TemplateModel createModel(Class clazz) { Object[] obj = clazz.getEnumConstants(); if(obj == null) { // Return null - it'll manifest itself as undefined in the template. // We're doing this rather than throw an exception as this way // people can use someEnumModel?default({}) to gracefully fall back // to an empty hash if they want to. return null; } Map map = new LinkedHashMap(); for (int i = 0; i < obj.length; i++) { Enum value = (Enum) obj[i]; map.put(value.name(), value); } return new SimpleMapModel(map, getWrapper()); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/HashAdapter.java0000644000175000017500000001257511723544472025502 0ustar ebourgebourgpackage freemarker.ext.beans; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelAdapter; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: HashAdapter.java,v 1.2 2005/06/12 19:03:04 szegedia Exp $ */ public class HashAdapter extends AbstractMap implements TemplateModelAdapter { private final BeansWrapper wrapper; private final TemplateHashModel model; private Set entrySet; HashAdapter(TemplateHashModel model, BeansWrapper wrapper) { this.model = model; this.wrapper = wrapper; } public TemplateModel getTemplateModel() { return model; } public boolean isEmpty() { try { return model.isEmpty(); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public Object get(Object key) { try { return wrapper.unwrap(model.get(String.valueOf(key))); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public boolean containsKey(Object key) { // A quick check that doesn't require TemplateHashModelEx if(get(key) != null) { return true; } return super.containsKey(key); } public Set entrySet() { if(entrySet != null) { return entrySet; } return entrySet = new AbstractSet() { public Iterator iterator() { final TemplateModelIterator i; try { i = getModelEx().keys().iterator(); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } return new Iterator() { public boolean hasNext() { try { return i.hasNext(); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public Object next() { final Object key; try { key = wrapper.unwrap(i.next()); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } return new Map.Entry() { public Object getKey() { return key; } public Object getValue() { return get(key); } public Object setValue(Object value) { throw new UnsupportedOperationException(); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } public int hashCode() { Object value = getValue(); return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); } }; } public void remove() { throw new UnsupportedOperationException(); } }; } public int size() { try { return getModelEx().size(); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } }; } private TemplateHashModelEx getModelEx() { if(model instanceof TemplateHashModelEx) { return ((TemplateHashModelEx)model); } throw new UnsupportedOperationException( "Operation supported only on TemplateHashModelEx. " + model.getClass().getName() + " does not implement it though."); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/MethodUtilities.java0000644000175000017500000002224411723544471026423 0ustar ebourgebourg/* * Copyright (c) 2003-2007 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import freemarker.template.utility.UndeclaredThrowableException; class MethodUtilities { static final Class OBJECT_CLASS = Object.class; private static final Method METHOD_IS_VARARGS = getIsVarArgsMethod(Method.class); private static final Method CONSTRUCTOR_IS_VARARGS = getIsVarArgsMethod(Constructor.class); static Class getMostSpecificCommonType(Class c1, Class c2) { if(c1 == c2) { return c1; } if(c2.isPrimitive()) { if(c2 == Byte.TYPE) c2 = Byte.class; else if(c2 == Short.TYPE) c2 = Short.class; else if(c2 == Character.TYPE) c2 = Character.class; else if(c2 == Integer.TYPE) c2 = Integer.class; else if(c2 == Float.TYPE) c2 = Float.class; else if(c2 == Long.TYPE) c2 = Long.class; else if(c2 == Double.TYPE) c2 = Double.class; } Set a1 = getAssignables(c1, c2); Set a2 = getAssignables(c2, c1); a1.retainAll(a2); if(a1.isEmpty()) { // Can happen when at least one of the arguments is an interface, as // they don't have Object at the root of their hierarchy return Object.class; } // Gather maximally specific elements. Yes, there can be more than one // thank to interfaces. I.e., if you call this method for String.class // and Number.class, you'll have Comparable, Serializable, and Object as // maximal elements. List max = new ArrayList(); outer: for (Iterator it = a1.iterator(); it.hasNext();) { Class clazz = (Class)it.next(); for (Iterator maxiter = max.iterator(); maxiter.hasNext();) { Class maxClazz = (Class)maxiter.next(); if(isMoreSpecific(maxClazz, clazz)) { // It can't be maximal, if there's already a more specific // maximal than it. continue outer; } if(isMoreSpecific(clazz, maxClazz)) { // If it's more specific than a currently maximal element, // that currently maximal is no longer a maximal. maxiter.remove(); } } // If we get here, no current maximal is more specific than the // current class, so it is considered maximal as well max.add(clazz); } if(max.size() > 1) { return OBJECT_CLASS; } return (Class)max.get(0); } /** * Determines whether a type represented by a class object is * convertible to another type represented by a class object using a * method invocation conversion, without matching object and primitive * types. This method is used to determine the more specific type when * comparing signatures of methods. * @return true if either formal type is assignable from actual type, * or formal and actual are both primitive types and actual can be * subject to widening conversion to formal. */ static boolean isMoreSpecific(Class specific, Class generic) { // Check for identity or widening reference conversion if(generic.isAssignableFrom(specific)) { return true; } // Check for widening primitive conversion. if(generic.isPrimitive()) { if(generic == Short.TYPE && (specific == Byte.TYPE)) { return true; } if(generic == Integer.TYPE && (specific == Short.TYPE || specific == Byte.TYPE)) { return true; } if(generic == Long.TYPE && (specific == Integer.TYPE || specific == Short.TYPE || specific == Byte.TYPE)) { return true; } if(generic == Float.TYPE && (specific == Long.TYPE || specific == Integer.TYPE || specific == Short.TYPE || specific == Byte.TYPE)) { return true; } if(generic == Double.TYPE && (specific == Float.TYPE || specific == Long.TYPE || specific == Integer.TYPE || specific == Short.TYPE || specific == Byte.TYPE)) { return true; } } return false; } private static Set getAssignables(Class c1, Class c2) { Set s = new HashSet(); collectAssignables(c1, c2, s); return s; } private static void collectAssignables(Class c1, Class c2, Set s) { if(c1.isAssignableFrom(c2)) { s.add(c1); } Class sc = c1.getSuperclass(); if(sc != null) { collectAssignables(sc, c2, s); } Class[] itf = c1.getInterfaces(); for(int i = 0; i < itf.length; ++i) { collectAssignables(itf[i], c2, s); } } static Class[] getParameterTypes(Member member) { if(member instanceof Method) { return ((Method)member).getParameterTypes(); } if(member instanceof Constructor) { return ((Constructor)member).getParameterTypes(); } throw new RuntimeException(); } static boolean isVarArgs(Member member) { if(member instanceof Method) { return isVarArgs(member, METHOD_IS_VARARGS); } if(member instanceof Constructor) { return isVarArgs(member, CONSTRUCTOR_IS_VARARGS); } throw new RuntimeException(); } private static boolean isVarArgs(Member member, Method isVarArgsMethod) { if(isVarArgsMethod == null) { return false; } try { return ((Boolean)isVarArgsMethod.invoke(member, (Object[]) null)).booleanValue(); } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new UndeclaredThrowableException(e); } } private static Method getIsVarArgsMethod(Class memberClass) { try { return memberClass.getMethod("isVarArgs", (Class[]) null); } catch(NoSuchMethodException e) { return null; // pre 1.5 JRE } } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/JavaRebelIntegration.java0000644000175000017500000000310311723544471027337 0ustar ebourgebourgpackage freemarker.ext.beans; import java.lang.ref.WeakReference; import org.zeroturnaround.javarebel.ClassEventListener; import org.zeroturnaround.javarebel.ReloaderFactory; /** * @author Attila Szegedi * @version $Id: $ */ class JavaRebelIntegration { static void testAvailability() { ReloaderFactory.getInstance(); } /** * Adds a JavaRebel class reloading listener for a that will invalidate * cached information for that class in the specified BeansWrapper when the * class is reloaded. The beans wrapper is weakly referenced and the * listener is unregistered if the wrapper is garbage collected. * @param w the beans wrapper to register. */ static void registerWrapper(BeansWrapper w) { ReloaderFactory.getInstance().addClassReloadListener( new BeansWrapperCacheInvalidator(w)); } private static class BeansWrapperCacheInvalidator implements ClassEventListener { private final WeakReference ref; BeansWrapperCacheInvalidator(BeansWrapper w) { ref = new WeakReference(w); } public void onClassEvent(int eventType, Class klass) { BeansWrapper wrapper = (BeansWrapper)ref.get(); if(wrapper == null) { ReloaderFactory.getInstance().removeClassReloadListener(this); } else if(eventType == ClassEventListener.EVENT_RELOADED) { wrapper.removeIntrospectionInfo(klass); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/ArrayModel.java0000644000175000017500000001335111723544470025344 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Array; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateSequenceModel; /** *

A class that will wrap an arbitrary array into {@link TemplateCollectionModel} * and {@link TemplateSequenceModel} interfaces. It supports element retrieval through the array[index] * syntax and can be iterated as a list. * @author Attila Szegedi * @version $Id: ArrayModel.java,v 1.26 2003/06/03 13:21:32 szegedia Exp $ */ public class ArrayModel extends BeanModel implements TemplateCollectionModel, TemplateSequenceModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new ArrayModel(object, (BeansWrapper)wrapper); } }; // Cached length of the array private int length; /** * Creates a new model that wraps the specified array object. * @param array the array object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. * @throws IllegalArgumentException if the passed object is not a Java array. */ public ArrayModel(Object array, BeansWrapper wrapper) { super(array, wrapper); Class clazz = array.getClass(); if(!clazz.isArray()) throw new IllegalArgumentException("Object is not an array, it is " + array.getClass().getName()); length = Array.getLength(array); } public TemplateModelIterator iterator() { return new Iterator(); } public TemplateModel get(int index) throws TemplateModelException { try { return wrap(Array.get(object, index)); } catch(IndexOutOfBoundsException e) { return null; // throw new TemplateModelException("Index out of bounds: " + index); } } private class Iterator implements TemplateSequenceModel, TemplateModelIterator { private int position = 0; public boolean hasNext() { return position < length; } public TemplateModel get(int index) throws TemplateModelException { return ArrayModel.this.get(index); } public TemplateModel next() throws TemplateModelException { return position < length ? get(position++) : null; } public int size() { return ArrayModel.this.size(); } } public int size() { return length; } public boolean isEmpty() { return length == 0; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/ResourceBundleModel.java0000644000175000017500000002054411723544470027211 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.text.MessageFormat; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** *

A hash model that wraps a resource bundle. Makes it convenient to store * localized content in the data model. It also acts as a method model that will * take a resource key and arbitrary number of arguments and will apply * {@link MessageFormat} with arguments on the string represented by the key.

* *

Typical usages:

*
    *
  • bundle.resourceKey will retrieve the object from resource bundle * with key resourceKey
  • *
  • bundle("patternKey", arg1, arg2, arg3) will retrieve the string * from resource bundle with key patternKey, and will use it as a pattern * for MessageFormat with arguments arg1, arg2 and arg3
  • *
* @author Attila Szegedi * @version $Id: ResourceBundleModel.java,v 1.22.2.2 2007/04/02 13:19:37 szegedia Exp $ */ public class ResourceBundleModel extends BeanModel implements TemplateMethodModelEx { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new ResourceBundleModel((ResourceBundle)object, (BeansWrapper)wrapper); } }; private Hashtable formats = null; public ResourceBundleModel(ResourceBundle bundle, BeansWrapper wrapper) { super(bundle, wrapper); } /** * Overridden to invoke the getObject method of the resource bundle. */ protected TemplateModel invokeGenericGet(Map keyMap, Class clazz, String key) throws TemplateModelException { try { return wrap(((ResourceBundle)object).getObject(key)); } catch(MissingResourceException e) { throw new TemplateModelException("No such key: " + key); } } /** * Returns true if this bundle contains no objects. */ public boolean isEmpty() { return !((ResourceBundle)object).getKeys().hasMoreElements() && super.isEmpty(); } public int size() { return keySet().size(); } protected Set keySet() { Set set = super.keySet(); Enumeration e = ((ResourceBundle)object).getKeys(); while (e.hasMoreElements()) { set.add(e.nextElement()); } return set; } /** * Takes first argument as a resource key, looks up a string in resource bundle * with this key, then applies a MessageFormat.format on the string with the * rest of the arguments. The created MessageFormats are cached for later reuse. */ public Object exec(List arguments) throws TemplateModelException { // Must have at least one argument - the key if(arguments.size() < 1) throw new TemplateModelException("No message key was specified"); // Read it Iterator it = arguments.iterator(); String key = unwrap((TemplateModel)it.next()).toString(); try { if(!it.hasNext()) { return wrap(((ResourceBundle)object).getObject(key)); } // Copy remaining arguments into an Object[] int args = arguments.size() - 1; Object[] params = new Object[args]; for(int i = 0; i < args; ++i) params[i] = unwrap((TemplateModel)it.next()); // Invoke format return new StringModel(format(key, params), wrapper); } catch(MissingResourceException e) { throw new TemplateModelException("No such key: " + key); } catch(Exception e) { throw new TemplateModelException(e.getMessage()); } } /** * Provides direct access to caching format engine from code (instead of from script). */ public String format(String key, Object[] params) throws MissingResourceException { // Check to see if we already have a cache for message formats // and construct it if we don't // NOTE: this block statement should be synchronized. However // concurrent creation of two caches will have no harmful // consequences, and we avoid a performance hit. /* synchronized(this) */ { if(formats == null) formats = new Hashtable(); } MessageFormat format = null; // Check to see if we already have a requested MessageFormat cached // and construct it if we don't // NOTE: this block statement should be synchronized. However // concurrent creation of two formats will have no harmful // consequences, and we avoid a performance hit. /* synchronized(formats) */ { format = (MessageFormat)formats.get(key); if(format == null) { format = new MessageFormat(((ResourceBundle)object).getString(key)); format.setLocale(getBundle().getLocale()); formats.put(key, format); } } // Perform the formatting. We synchronize on it in case it // contains date formatting, which is not thread-safe. synchronized(format) { return format.format(params); } } public ResourceBundle getBundle() { return (ResourceBundle)object; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/DateModel.java0000644000175000017500000001045711723544470025147 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.util.Date; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateModel; /** * Wraps arbitrary subclass of {@link java.util.Date} into a reflective model. * Beside acting as a {@link TemplateDateModel}, you can call all Java methods * on these objects as well. */ public class DateModel extends BeanModel implements TemplateDateModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new DateModel((Date)object, (BeansWrapper)wrapper); } }; private final int type; /** * Creates a new model that wraps the specified date object. * @param date the date object to wrap into a model. * @param wrapper the {@link BeansWrapper} associated with this model. * Every model has to have an associated {@link BeansWrapper} instance. The * model gains many attributes from its wrapper, including the caching * behavior, method exposure level, method-over-item shadowing policy etc. */ public DateModel(Date date, BeansWrapper wrapper) { super(date, wrapper); if(date instanceof java.sql.Date) { type = DATE; } else if(date instanceof java.sql.Time) { type = TIME; } else if(date instanceof java.sql.Timestamp) { type = DATETIME; } else { type = wrapper.getDefaultDateType(); } } public Date getAsDate() { return (Date)object; } public int getDateType() { return type; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/unsafeMethods.txt0000644000175000017500000000615211723544471026012 0ustar ebourgebourgjava.lang.Object.wait() java.lang.Object.wait(long) java.lang.Object.wait(long,int) java.lang.Object.notify() java.lang.Object.notifyAll() java.lang.Class.getClassLoader() java.lang.Class.newInstance() java.lang.Class.forName(java.lang.String) java.lang.Class.forName(java.lang.String,boolean,java.lang.ClassLoader) java.lang.reflect.Constructor.newInstance([Ljava.lang.Object;) java.lang.reflect.Method.invoke(java.lang.Object,[Ljava.lang.Object;) java.lang.reflect.Field.set(java.lang.Object,java.lang.Object) java.lang.reflect.Field.setBoolean(java.lang.Object,boolean) java.lang.reflect.Field.setByte(java.lang.Object,byte) java.lang.reflect.Field.setChar(java.lang.Object,char) java.lang.reflect.Field.setDouble(java.lang.Object,double) java.lang.reflect.Field.setFloat(java.lang.Object,float) java.lang.reflect.Field.setInt(java.lang.Object,int) java.lang.reflect.Field.setLong(java.lang.Object,long) java.lang.reflect.Field.setShort(java.lang.Object,short) java.lang.reflect.AccessibleObject.setAccessible([Ljava.lang.reflect.AccessibleObject;,boolean) java.lang.reflect.AccessibleObject.setAccessible(boolean) java.lang.Thread.destroy() java.lang.Thread.getContextClassLoader() java.lang.Thread.interrupt() java.lang.Thread.join() java.lang.Thread.join(long) java.lang.Thread.join(long,int) java.lang.Thread.resume() java.lang.Thread.run() java.lang.Thread.setContextClassLoader(java.lang.ClassLoader) java.lang.Thread.setDaemon(boolean) java.lang.Thread.setName(java.lang.String) java.lang.Thread.setPriority(int) java.lang.Thread.sleep(long) java.lang.Thread.sleep(long,int) java.lang.Thread.start() java.lang.Thread.stop() java.lang.Thread.stop(java.lang.Throwable) java.lang.Thread.suspend() java.lang.ThreadGroup.allowThreadSuspension(boolean) java.lang.ThreadGroup.destroy() java.lang.ThreadGroup.interrupt() java.lang.ThreadGroup.resume() java.lang.ThreadGroup.setDaemon(boolean) java.lang.ThreadGroup.setMaxPriority(int) java.lang.ThreadGroup.stop() java.lang.Thread.suspend() java.lang.Runtime.addShutdownHook(java.lang.Thread) java.lang.Runtime.exec(java.lang.String) java.lang.Runtime.exec([Ljava.lang.String;) java.lang.Runtime.exec([Ljava.lang.String;,[Ljava.lang.String;) java.lang.Runtime.exec([Ljava.lang.String;,[Ljava.lang.String;,java.io.File) java.lang.Runtime.exec(java.lang.String,[Ljava.lang.String;) java.lang.Runtime.exec(java.lang.String,[Ljava.lang.String;,java.io.File) java.lang.Runtime.exit(int) java.lang.Runtime.halt(int) java.lang.Runtime.load(java.lang.String) java.lang.Runtime.loadLibrary(java.lang.String) java.lang.Runtime.removeShutdownHook(java.lang.Thread) java.lang.Runtime.traceInstructions(boolean) java.lang.Runtime.traceMethodCalls(boolean) java.lang.System.exit(int) java.lang.System.load(java.lang.String) java.lang.System.loadLibrary(java.lang.String) java.lang.System.runFinalizersOnExit(boolean) java.lang.System.setErr(java.io.PrintStream) java.lang.System.setIn(java.io.InputStream) java.lang.System.setOut(java.io.PrintStream) java.lang.System.setProperties(java.util.Properties) java.lang.System.setProperty(java.lang.String,java.lang.String) java.lang.System.setSecurityManager(java.lang.SecurityManager) libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/OverloadedMethod.java0000644000175000017500000001261611723544470026535 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Member; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import freemarker.template.TemplateModelException; /** * @author Attila Szegedi * @version $Id: $ */ abstract class OverloadedMethod { static final Object NO_SUCH_METHOD = new Object(); static final Object AMBIGUOUS_METHOD = new Object(); static final Object[] EMPTY_ARGS = new Object[0]; private Class[][] marshalTypes; // TODO: make it not concurrent private final Map selectorCache = new HashMap(); private final List members = new LinkedList(); private final Map signatures = new HashMap(); void addMember(Member member) { members.add(member); Class[] argTypes = MethodUtilities.getParameterTypes(member); int l = argTypes.length; signatures.put(member, argTypes.clone()); onAddSignature(member, argTypes); if(marshalTypes == null) { marshalTypes = new Class[l + 1][]; marshalTypes[l] = argTypes; updateSignature(l); } else if(marshalTypes.length <= l) { Class[][] newMarshalTypes = new Class[l + 1][]; System.arraycopy(marshalTypes, 0, newMarshalTypes, 0, marshalTypes.length); marshalTypes = newMarshalTypes; marshalTypes[l] = argTypes; updateSignature(l); } else { Class[] oldTypes = marshalTypes[l]; if(oldTypes == null) { marshalTypes[l] = argTypes; } else { for(int i = 0; i < oldTypes.length; ++i) { oldTypes[i] = MethodUtilities.getMostSpecificCommonType(oldTypes[i], argTypes[i]); } } updateSignature(l); } afterSignatureAdded(l); } Class[] getSignature(Member member) { return (Class[])signatures.get(member); } Class[][] getMarshalTypes() { return marshalTypes; } Object getMemberForArgs(Object[] args, boolean varArg) { ClassString argTypes = new ClassString(args); Object objMember; synchronized(selectorCache) { objMember = selectorCache.get(argTypes); if(objMember == null) { objMember = argTypes.getMostSpecific(members, varArg); selectorCache.put(argTypes, objMember); } } return objMember; } abstract void onAddSignature(Member member, Class[] argTypes); abstract void updateSignature(int l); abstract void afterSignatureAdded(int l); abstract Object getMemberAndArguments(List arguments, BeansWrapper w) throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/InvalidPropertyException.java0000644000175000017500000000065111723544470030316 0ustar ebourgebourgpackage freemarker.ext.beans; import freemarker.template.TemplateModelException; /** * An exception thrown when there is an attempt to access * an invalid bean property when we are in a "strict bean" mode * @author Jonathan Revusky */ public class InvalidPropertyException extends TemplateModelException { public InvalidPropertyException(String description) { super(description); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/OverloadedFixArgMethod.java0000644000175000017500000001064211723544471027634 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Member; import java.util.Collections; import java.util.Iterator; import java.util.List; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * @author Attila Szegedi * @version $Id: $ */ class OverloadedFixArgMethod extends OverloadedMethod { void onAddSignature(Member member, Class[] argTypes) { }; void updateSignature(int l) { }; void afterSignatureAdded(int l) { }; Object getMemberAndArguments(List arguments, BeansWrapper w) throws TemplateModelException { if(arguments == null) { // null is treated as empty args arguments = Collections.EMPTY_LIST; } int l = arguments.size(); Class[][] marshalTypes = getMarshalTypes(); if(marshalTypes.length <= l) { return NO_SUCH_METHOD; } Class[] types = marshalTypes[l]; if(types == null) { return NO_SUCH_METHOD; } //assert types.length == l; // Marshal the arguments Object[] args = new Object[l]; Iterator it = arguments.iterator(); for(int i = 0; i < l; ++i) { Object obj = w.unwrapInternal((TemplateModel)it.next(), types[i]); if(obj == BeansWrapper.CAN_NOT_UNWRAP) { return NO_SUCH_METHOD; } args[i] = obj; } Object objMember = getMemberForArgs(args, false); if(objMember instanceof Member) { Member member = (Member)objMember; BeansWrapper.coerceBigDecimals(getSignature(member), args); return new MemberAndArguments(member, args); } return objMember; // either NO_SUCH_METHOD or AMBIGUOUS_METHOD } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/MethodMap.java0000644000175000017500000001040011723544472025155 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.Member; import java.util.List; import freemarker.template.TemplateModelException; class MethodMap { private final String name; private final BeansWrapper wrapper; private final OverloadedMethod fixArgMethod = new OverloadedFixArgMethod(); private OverloadedMethod varArgMethod; MethodMap(String name, BeansWrapper wrapper) { this.name = name; this.wrapper = wrapper; } BeansWrapper getWrapper() { return wrapper; } void addMember(Member member) { fixArgMethod.addMember(member); if(MethodUtilities.isVarArgs(member)) { if(varArgMethod == null) { varArgMethod = new OverloadedVarArgMethod(); } varArgMethod.addMember(member); } } MemberAndArguments getMemberAndArguments(List arguments) throws TemplateModelException { Object memberAndArguments = fixArgMethod.getMemberAndArguments(arguments, wrapper); if(memberAndArguments == OverloadedMethod.NO_SUCH_METHOD) { if(varArgMethod != null) { memberAndArguments = varArgMethod.getMemberAndArguments(arguments, wrapper); } if(memberAndArguments == OverloadedMethod.NO_SUCH_METHOD) { throw new TemplateModelException("No signature of method " + name + " matches the arguments"); } } if(memberAndArguments == OverloadedMethod.AMBIGUOUS_METHOD) { throw new TemplateModelException("Multiple signatures of method " + name + " match the arguments"); } return (MemberAndArguments)memberAndArguments; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/CollectionAdapter.java0000644000175000017500000000401211723544471026674 0ustar ebourgebourgpackage freemarker.ext.beans; import java.util.AbstractCollection; import java.util.Iterator; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelAdapter; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: CollectionAdapter.java,v 1.2 2005/06/12 19:03:04 szegedia Exp $ */ class CollectionAdapter extends AbstractCollection implements TemplateModelAdapter { private final BeansWrapper wrapper; private final TemplateCollectionModel model; CollectionAdapter(TemplateCollectionModel model, BeansWrapper wrapper) { this.model = model; this.wrapper = wrapper; } public TemplateModel getTemplateModel() { return model; } public int size() { throw new UnsupportedOperationException(); } public Iterator iterator() { try { return new Iterator() { final TemplateModelIterator i = model.iterator(); public boolean hasNext() { try { return i.hasNext(); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public Object next() { try { return wrapper.unwrap(i.next()); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } public void remove() { throw new UnsupportedOperationException(); } }; } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/package.html0000644000175000017500000000124311723544471024721 0ustar ebourgebourg

Provides model implementations that allow access to arbitrary Java objects.

Most of the issues dealing with beans are handled by the {@link freemarker.ext.beans.BeansWrapper#wrap(Object)}and {@link freemarker.ext.beans.BeansWrapper#getStaticModels()} methods. In normal cases, these are the only methods you should use to turn an arbitrary Java object into a FreeMarker {@link freemarker.template.TemplateModel}. Additionally, you can manually create instance of any wrapper class using its constructors. Note, however that in such cases you bypass the eventual model caching of the wrapper.

libfreemarker-java-2.3.19.orig/src/freemarker/ext/beans/SimpleMethodModel.java0000644000175000017500000001312511723544470026657 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.beans; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import freemarker.template.SimpleNumber; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.Collections12; /** * A class that will wrap a reflected method call into a * {@link freemarker.template.TemplateMethodModel} interface. * It is used by {@link BeanModel} to wrap reflected method calls * for non-overloaded methods. * @author Attila Szegedi, szegedia at users dot sourceforge dot net * @version $Id: SimpleMethodModel.java,v 1.27 2005/06/11 12:12:04 szegedia Exp $ */ public final class SimpleMethodModel extends SimpleMemberModel implements TemplateMethodModelEx, TemplateSequenceModel { private final Object object; private final BeansWrapper wrapper; /** * Creates a model for a specific method on a specific object. * @param object the object to call the method on. Can be * null for static methods. * @param method the method that will be invoked. */ SimpleMethodModel(Object object, Method method, Class[] argTypes, BeansWrapper wrapper) { super(method, argTypes); this.object = object; this.wrapper = wrapper; } /** * Invokes the method, passing it the arguments from the list. */ public Object exec(List arguments) throws TemplateModelException { try { return wrapper.invokeMethod(object, (Method)getMember(), unwrapArguments(arguments, wrapper)); } catch(Exception e) { while(e instanceof InvocationTargetException) { Throwable t = ((InvocationTargetException)e).getTargetException(); if(t instanceof Exception) { e = (Exception)t; } else { break; } } if((getMember().getModifiers() & Modifier.STATIC) != 0) { throw new TemplateModelException("Method " + getMember() + " threw an exception", e); } else { throw new TemplateModelException("Method " + getMember() + " threw an exception when invoked on " + object, e); } } } public TemplateModel get(int index) throws TemplateModelException { return (TemplateModel) exec(Collections12.singletonList( new SimpleNumber(new Integer(index)))); } public int size() throws TemplateModelException { throw new TemplateModelException("?size is unsupported for: " + getClass().getName()); } public String toString() { return getMember().toString(); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/0000755000175000017500000000000012164627123022123 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/XPathSupport.java0000644000175000017500000000543711723544467025431 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; public interface XPathSupport { TemplateModel executeQuery(Object context, String xpathQuery) throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/DocumentTypeModel.java0000644000175000017500000000662511723544470026403 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import org.w3c.dom.*; import freemarker.template.*; class DocumentTypeModel extends NodeModel { public DocumentTypeModel(DocumentType docType) { super(docType); } public String getAsString() { return ((ProcessingInstruction) node).getData(); } public TemplateSequenceModel getChildren() throws TemplateModelException { throw new TemplateModelException("entering the child nodes of a DTD node is not currently supported"); } public TemplateModel get(String key) throws TemplateModelException { throw new TemplateModelException("accessing properties of a DTD is not currently supported"); } public String getNodeName() { return "@document_type$" + ((DocumentType) node).getNodeName(); } public boolean isEmpty() { return true; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/CharacterDataNodeModel.java0000644000175000017500000000606311723544471027254 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import org.w3c.dom.*; import freemarker.template.*; class CharacterDataNodeModel extends NodeModel implements TemplateScalarModel { public CharacterDataNodeModel(CharacterData text) { super(text); } public String getAsString() { return ((org.w3c.dom.CharacterData) node).getData(); } public String getNodeName() { return (node instanceof Comment) ? "@comment" : "@text"; } public boolean isEmpty() { return true; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/NodeModel.java0000644000175000017500000005550711723544470024653 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import java.io.File; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.CharacterData; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import freemarker.ext.util.WrapperTemplateModel; import freemarker.log.Logger; import freemarker.template.AdapterTemplateModel; import freemarker.template.SimpleScalar; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNodeModel; import freemarker.template.TemplateSequenceModel; /** * A base class for wrapping a W3C DOM Node as a FreeMarker template model. * @author Jonathan Revusky * @version $Id: NodeModel.java,v 1.80 2005/06/22 11:33:31 ddekany Exp $ */ abstract public class NodeModel implements TemplateNodeModel, TemplateHashModel, TemplateSequenceModel, AdapterTemplateModel, WrapperTemplateModel { static final Logger logger = Logger.getLogger("freemarker.dom"); static private DocumentBuilderFactory docBuilderFactory; static private Map xpathSupportMap = Collections.synchronizedMap(new WeakHashMap()); static private XPathSupport jaxenXPathSupport; static private ErrorHandler errorHandler; static Class xpathSupportClass; static { try { useDefaultXPathSupport(); } catch (Exception e) { // do nothing } if (xpathSupportClass == null && logger.isWarnEnabled()) { logger.warn("No XPath support is available."); } } /** * The W3C DOM Node being wrapped. */ final Node node; private TemplateSequenceModel children; private NodeModel parent; /** * Sets the DOM Parser implementation to be used when building NodeModel * objects from XML files. */ static public void setDocumentBuilderFactory(DocumentBuilderFactory docBuilderFactory) { NodeModel.docBuilderFactory = docBuilderFactory; } /** * @return the DOM Parser implementation that is used when * building NodeModel objects from XML files. */ static public DocumentBuilderFactory getDocumentBuilderFactory() { if (docBuilderFactory == null) { docBuilderFactory = DocumentBuilderFactory.newInstance(); docBuilderFactory.setNamespaceAware(true); docBuilderFactory.setIgnoringElementContentWhitespace(true); } return docBuilderFactory; } /** * sets the error handler to use when parsing the document. */ static public void setErrorHandler(ErrorHandler errorHandler) { NodeModel.errorHandler = errorHandler; } /** * Create a NodeModel from a SAX input source. Adjacent text nodes will be merged (and CDATA sections * are considered as text nodes). * @param removeComments whether to remove all comment nodes * (recursively) from the tree before processing * @param removePIs whether to remove all processing instruction nodes * (recursively from the tree before processing */ static public NodeModel parse(InputSource is, boolean removeComments, boolean removePIs) throws SAXException, IOException, ParserConfigurationException { DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); if (errorHandler != null) builder.setErrorHandler(errorHandler); Document doc = builder.parse(is); if (removeComments && removePIs) { simplify(doc); } else { if (removeComments) { removeComments(doc); } if (removePIs) { removePIs(doc); } mergeAdjacentText(doc); } return wrap(doc); } /** * Create a NodeModel from an XML input source. By default, * all comments and processing instruction nodes are * stripped from the tree. */ static public NodeModel parse(InputSource is) throws SAXException, IOException, ParserConfigurationException { return parse(is, true, true); } /** * Create a NodeModel from an XML file. * @param removeComments whether to remove all comment nodes * (recursively) from the tree before processing * @param removePIs whether to remove all processing instruction nodes * (recursively from the tree before processing */ static public NodeModel parse(File f, boolean removeComments, boolean removePIs) throws SAXException, IOException, ParserConfigurationException { DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); if (errorHandler != null) builder.setErrorHandler(errorHandler); Document doc = builder.parse(f); if (removeComments) { removeComments(doc); } if (removePIs) { removePIs(doc); } mergeAdjacentText(doc); return wrap(doc); } /** * Create a NodeModel from an XML file. By default, * all comments and processing instruction nodes are * stripped from the tree. */ static public NodeModel parse(File f) throws SAXException, IOException, ParserConfigurationException { return parse(f, true, true); } protected NodeModel(Node node) { this.node = node; } /** * @return the underling W3C DOM Node object that this TemplateNodeModel * is wrapping. */ public Node getNode() { return node; } public TemplateModel get(String key) throws TemplateModelException { if (key.startsWith("@@")) { if (key.equals("@@text")) { return new SimpleScalar(getText(node)); } if (key.equals("@@namespace")) { String nsURI = node.getNamespaceURI(); return nsURI == null ? null : new SimpleScalar(nsURI); } if (key.equals("@@local_name")) { String localName = node.getLocalName(); if (localName == null) { localName = getNodeName(); } return new SimpleScalar(localName); } if (key.equals("@@markup")) { StringBuffer buf = new StringBuffer(); NodeOutputter nu = new NodeOutputter(node); nu.outputContent(node, buf); return new SimpleScalar(buf.toString()); } if (key.equals("@@nested_markup")) { StringBuffer buf = new StringBuffer(); NodeOutputter nu = new NodeOutputter(node); nu.outputContent(node.getChildNodes(), buf); return new SimpleScalar(buf.toString()); } if (key.equals("@@qname")) { String qname = getQualifiedName(); return qname == null ? null : new SimpleScalar(qname); } } XPathSupport xps = getXPathSupport(); if (xps != null) { return xps.executeQuery(node, key); } else { throw new TemplateModelException( "Can't try to resolve the XML query key, because no XPath support is available. " + "It's either malformed or an XPath expression: " + key); } } public TemplateNodeModel getParentNode() { if (parent == null) { Node parentNode = node.getParentNode(); if (parentNode == null) { if (node instanceof Attr) { parentNode = ((Attr) node).getOwnerElement(); } } parent = wrap(parentNode); } return parent; } public TemplateSequenceModel getChildNodes() { if (children == null) { children = new NodeListModel(node.getChildNodes(), this); } return children; } public final String getNodeType() throws TemplateModelException { short nodeType = node.getNodeType(); switch (nodeType) { case Node.ATTRIBUTE_NODE : return "attribute"; case Node.CDATA_SECTION_NODE : return "text"; case Node.COMMENT_NODE : return "comment"; case Node.DOCUMENT_FRAGMENT_NODE : return "document_fragment"; case Node.DOCUMENT_NODE : return "document"; case Node.DOCUMENT_TYPE_NODE : return "document_type"; case Node.ELEMENT_NODE : return "element"; case Node.ENTITY_NODE : return "entity"; case Node.ENTITY_REFERENCE_NODE : return "entity_reference"; case Node.NOTATION_NODE : return "notation"; case Node.PROCESSING_INSTRUCTION_NODE : return "pi"; case Node.TEXT_NODE : return "text"; } throw new TemplateModelException("Unknown node type: " + nodeType + ". This should be impossible!"); } public TemplateModel exec(List args) throws TemplateModelException { if (args.size() != 1) { throw new TemplateModelException("Expecting exactly one arguments"); } String query = (String) args.get(0); // Now, we try to behave as if this is an XPath expression XPathSupport xps = getXPathSupport(); if (xps == null) { throw new TemplateModelException("No XPath support available"); } return xps.executeQuery(node, query); } public final int size() {return 1;} public final TemplateModel get(int i) { return i==0 ? this : null; } public String getNodeNamespace() { int nodeType = node.getNodeType(); if (nodeType != Node.ATTRIBUTE_NODE && nodeType != Node.ELEMENT_NODE) { return null; } String result = node.getNamespaceURI(); if (result == null && nodeType == Node.ELEMENT_NODE) { result = ""; } else if ("".equals(result) && nodeType == Node.ATTRIBUTE_NODE) { result = null; } return result; } public final int hashCode() { return node.hashCode(); } public boolean equals(Object other) { if (other == null) return false; return other.getClass() == this.getClass() && ((NodeModel) other).node.equals(this.node); } static public NodeModel wrap(Node node) { if (node == null) { return null; } NodeModel result = null; switch (node.getNodeType()) { case Node.DOCUMENT_NODE : result = new DocumentModel((Document) node); break; case Node.ELEMENT_NODE : result = new ElementModel((Element) node); break; case Node.ATTRIBUTE_NODE : result = new AttributeNodeModel((Attr) node); break; case Node.CDATA_SECTION_NODE : case Node.COMMENT_NODE : case Node.TEXT_NODE : result = new CharacterDataNodeModel((org.w3c.dom.CharacterData) node); break; case Node.PROCESSING_INSTRUCTION_NODE : result = new PINodeModel((ProcessingInstruction) node); break; case Node.DOCUMENT_TYPE_NODE : result = new DocumentTypeModel((DocumentType) node); break; } return result; } /** * Recursively removes all comment nodes * from the subtree. * * @see #simplify */ static public void removeComments(Node node) { NodeList children = node.getChildNodes(); int i = 0; int len = children.getLength(); while (i < len) { Node child = children.item(i); if (child.hasChildNodes()) { removeComments(child); i++; } else { if (child.getNodeType() == Node.COMMENT_NODE) { node.removeChild(child); len--; } else { i++; } } } } /** * Recursively removes all processing instruction nodes * from the subtree. * * @see #simplify */ static public void removePIs(Node node) { NodeList children = node.getChildNodes(); int i = 0; int len = children.getLength(); while (i < len) { Node child = children.item(i); if (child.hasChildNodes()) { removePIs(child); i++; } else { if (child.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { node.removeChild(child); len--; } else { i++; } } } } /** * Merges adjacent text/cdata nodes, so that there are no * adjacent text/cdata nodes. Operates recursively * on the entire subtree. You thus lose information * about any CDATA sections occurring in the doc. * * @see #simplify */ static public void mergeAdjacentText(Node node) { Node child = node.getFirstChild(); while (child != null) { if (child instanceof Text || child instanceof CDATASection) { Node next = child.getNextSibling(); if (next instanceof Text || next instanceof CDATASection) { String fullText = child.getNodeValue() + next.getNodeValue(); ((CharacterData) child).setData(fullText); node.removeChild(next); } } else { mergeAdjacentText(child); } child = child.getNextSibling(); } } /** * Removes comments and processing instruction, and then unites adjacent text nodes. * Note that CDATA sections count as text nodes. */ static public void simplify(Node node) { NodeList children = node.getChildNodes(); int i = 0; int len = children.getLength(); Node prevTextChild = null; while (i < len) { Node child = children.item(i); if (child.hasChildNodes()) { simplify(child); prevTextChild = null; i++; } else { int type = child.getNodeType(); if (type == Node.PROCESSING_INSTRUCTION_NODE) { node.removeChild(child); len--; } else if (type == Node.COMMENT_NODE) { node.removeChild(child); len--; } else if (type == Node.TEXT_NODE || type == Node.CDATA_SECTION_NODE ) { if (prevTextChild != null) { CharacterData ptc = (CharacterData) prevTextChild; ptc.setData(ptc.getNodeValue() + child.getNodeValue()); node.removeChild(child); len--; } else { prevTextChild = child; i++; } } else { prevTextChild = null; i++; } } } } NodeModel getDocumentNodeModel() { if (node instanceof Document) { return this; } else { return wrap(node.getOwnerDocument()); } } /** * Tells the system to use (restore) the default (initial) XPath system used by * this FreeMarker version on this system. */ static public void useDefaultXPathSupport() { xpathSupportClass = null; jaxenXPathSupport = null; try { useXalanXPathSupport(); } catch (Exception e) { ; // ignore } if (xpathSupportClass == null) try { useSunInternalXPathSupport(); } catch (Exception e) { ; // ignore } if (xpathSupportClass == null) try { useJaxenXPathSupport(); } catch (Exception e) { ; // ignore } } /** * Convenience method. Tells the system to use Jaxen for XPath queries. * @throws Exception if the Jaxen classes are not present. */ static public void useJaxenXPathSupport() throws Exception { Class.forName("org.jaxen.dom.DOMXPath"); Class c = Class.forName("freemarker.ext.dom.JaxenXPathSupport"); jaxenXPathSupport = (XPathSupport) c.newInstance(); if (logger.isDebugEnabled()) { logger.debug("Using Jaxen classes for XPath support"); } xpathSupportClass = c; } /** * Convenience method. Tells the system to use Xalan for XPath queries. * @throws Exception if the Xalan XPath classes are not present. */ static public void useXalanXPathSupport() throws Exception { Class.forName("org.apache.xpath.XPath"); Class c = Class.forName("freemarker.ext.dom.XalanXPathSupport"); if (logger.isDebugEnabled()) { logger.debug("Using Xalan classes for XPath support"); } xpathSupportClass = c; } static public void useSunInternalXPathSupport() throws Exception { Class.forName("com.sun.org.apache.xpath.internal.XPath"); Class c = Class.forName("freemarker.ext.dom.SunInternalXalanXPathSupport"); if (logger.isDebugEnabled()) { logger.debug("Using Sun's internal Xalan classes for XPath support"); } xpathSupportClass = c; } /** * Set an alternative implementation of freemarker.ext.dom.XPathSupport to use * as the XPath engine. * @param cl the class, or null to disable XPath support. */ static public void setXPathSupportClass(Class cl) { if (cl != null && !XPathSupport.class.isAssignableFrom(cl)) { throw new RuntimeException("Class " + cl.getName() + " does not implement freemarker.ext.dom.XPathSupport"); } xpathSupportClass = cl; } /** * Get the currently used freemarker.ext.dom.XPathSupport used as the XPath engine. * Returns null if XPath support is disabled. */ static public Class getXPathSupportClass() { return xpathSupportClass; } static private String getText(Node node) { String result = ""; if (node instanceof Text || node instanceof CDATASection) { result = ((org.w3c.dom.CharacterData) node).getData(); } else if (node instanceof Element) { NodeList children = node.getChildNodes(); for (int i= 0; i0) { xpathSupport = ((NodeModel) get(0)).getXPathSupport(); } } return xpathSupport; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/Transform.java0000644000175000017500000002227411723544471024754 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import java.io.*; import java.util.*; import freemarker.core.Environment; import freemarker.template.*; /** * A class that contains a main() method for command-line invocation * of a FreeMarker XML transformation. * * $id$ */ public class Transform { private File inputFile, ftlFile, outputFile; private String encoding; private Locale locale; private Configuration cfg; /** * A convenient main() method for command-line invocation. */ static public void main(String[] args) { try { Transform proc = transformFromArgs(args); proc.transform(); } catch (IllegalArgumentException iae) { System.err.println(iae.getMessage()); usage(); } catch (Exception e) { e.printStackTrace(); } } /** * @param inputFile The file from which to read the XML input * @param ftlFile The file containing the template * @param outputFile The file to which to output. If this is null, we use stdout. * @param locale The locale to use. If this is null, we use the platform default. * @param encoding The character encoding to use for output, if this is null, we use the platform default */ Transform(File inputFile, File ftlFile, File outputFile, Locale locale, String encoding) throws IOException { if (encoding == null) { encoding = System.getProperty("file.encoding"); } if (locale == null) { locale = Locale.getDefault(); } this.encoding = encoding; this.locale = locale; this.inputFile = inputFile; this.ftlFile = ftlFile; this.outputFile = outputFile; File ftlDirectory = ftlFile.getAbsoluteFile().getParentFile(); cfg = new Configuration(); cfg.setDirectoryForTemplateLoading(ftlDirectory); } /** * Performs the transformation. */ void transform() throws Exception { String templateName = ftlFile.getName(); Template template = cfg.getTemplate(templateName, locale); NodeModel rootNode = NodeModel.parse(inputFile); OutputStream outputStream = System.out; if (outputFile != null) { outputStream = new FileOutputStream(outputFile); } Writer outputWriter = new OutputStreamWriter(outputStream, encoding); try { template.process(null, outputWriter, null, rootNode); } finally { if (outputFile != null) outputWriter.close(); } } static Transform transformFromArgs(String[] args) throws IOException { int i=0; String input = null, output=null, ftl = null, loc = null, enc = null; while (i=args.length) { throw new IllegalArgumentException(""); } String arg = args[i++]; if (dashArg.equals("-in")) { if (input != null) { throw new IllegalArgumentException("The input file should only be specified once"); } input = arg; } else if (dashArg.equals("-ftl")) { if (ftl != null) { throw new IllegalArgumentException("The ftl file should only be specified once"); } ftl = arg; } else if (dashArg.equals("-out")) { if (output != null) { throw new IllegalArgumentException("The output file should only be specified once"); } output = arg; } else if (dashArg.equals("-locale")) { if (loc != null) { throw new IllegalArgumentException("The locale should only be specified once"); } loc = arg; } else if (dashArg.equals("-encoding")) { if (enc != null) { throw new IllegalArgumentException("The encoding should only be specified once"); } enc = arg; } else { throw new IllegalArgumentException("Unknown input argument: " + dashArg); } } if (input == null) { throw new IllegalArgumentException("No input file specified."); } if (ftl == null) { throw new IllegalArgumentException("No ftl file specified."); } File inputFile = new File(input).getAbsoluteFile(); File ftlFile = new File(ftl).getAbsoluteFile(); if (!inputFile.exists()) { throw new IllegalArgumentException("Input file does not exist: " + input); } if (!ftlFile.exists()) { throw new IllegalArgumentException("FTL file does not exist: " + ftl); } if (!inputFile.isFile() || !inputFile.canRead()) { throw new IllegalArgumentException("Input file must be a readable file: " + input); } if (!ftlFile.isFile() || !ftlFile.canRead()) { throw new IllegalArgumentException("FTL file must be a readable file: " + ftl); } File outputFile = null; if (output != null) { outputFile = new File(output).getAbsoluteFile(); File outputDirectory = outputFile.getParentFile(); if (!outputDirectory.exists() || !outputDirectory.canWrite()) { throw new IllegalArgumentException("The output directory must exist and be writable: " + outputDirectory); } } Locale locale = Locale.getDefault(); if (loc != null) { locale = localeFromString(loc); } return new Transform(inputFile, ftlFile, outputFile, locale, enc); } static Locale localeFromString(String ls) { if (ls == null) ls = ""; String lang="", country="", variant=""; StringTokenizer st = new StringTokenizer(ls, "_-,"); if (st.hasMoreTokens()) { lang = st.nextToken(); if (st.hasMoreTokens()) { country = st.nextToken(); if (st.hasMoreTokens()) { variant = st.nextToken(); } } return new Locale(lang, country, variant); } else { return Locale.getDefault(); } } static void usage() { System.err.println("Usage: java freemarker.ext.dom.Transform -in -ftl [-out ] [-locale ] [-encoding ]"); // Security: prevents shutting down the container from a template: if (Environment.getCurrentEnvironment() == null) { System.exit(-1); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/XalanXPathSupport.java0000644000175000017500000001667011723544472026412 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import freemarker.template.*; import freemarker.core.Environment; import org.w3c.dom.*; import org.w3c.dom.traversal.NodeIterator; import org.apache.xpath.*; import org.apache.xpath.objects.*; import org.apache.xml.utils.PrefixResolver; import java.util.List; import javax.xml.transform.TransformerException; /** * Some glue code that bridges the Xalan XPath stuff (that is built into the JDK 1.4.x) * with FreeMarker TemplateModel semantics * @author Jonathan Revusky * @version $Id: XalanXPathSupport.java,v 1.20 2004/01/02 20:20:23 ddekany Exp $ */ class XalanXPathSupport implements XPathSupport { private XPathContext xpathContext = new XPathContext(); /* I don't recommend Jaxen... private static final String ERRMSG_RECOMMEND_JAXEN = "(Note that there is no such restriction if you " + "configure FreeMarker to use Jaxen instead of Xalan.)"; */ private static final String ERRMSG_EMPTY_NODE_SET = "Cannot perform an XPath query against an empty node set."; /* " + ERRMSG_RECOMMEND_JAXEN;*/ synchronized public TemplateModel executeQuery(Object context, String xpathQuery) throws TemplateModelException { if (!(context instanceof Node)) { if (context != null) { if (isNodeList(context)) { int cnt = ((List) context).size(); if (cnt != 0) { throw new TemplateModelException( "Cannot perform an XPath query against a node set of " + cnt + " nodes. Expecting a single node."/* " + ERRMSG_RECOMMEND_JAXEN*/); } else { throw new TemplateModelException(ERRMSG_EMPTY_NODE_SET); } } else { throw new TemplateModelException( "Cannot perform an XPath query against a " + context.getClass().getName() + ". Expecting a single org.w3c.dom.Node."); } } else { throw new TemplateModelException(ERRMSG_EMPTY_NODE_SET); } } Node node = (Node) context; try { XPath xpath = new XPath(xpathQuery, null, customPrefixResolver, XPath.SELECT, null); int ctxtNode = xpathContext.getDTMHandleFromNode(node); XObject xresult = xpath.execute(xpathContext, ctxtNode, customPrefixResolver); if (xresult instanceof XNodeSet) { NodeListModel result = new NodeListModel(node); result.xpathSupport = this; NodeIterator nodeIterator = xresult.nodeset(); Node n; do { n = nodeIterator.nextNode(); if (n != null) { result.add(n); } } while (n != null); return result.size() == 1 ? result.get(0) : result; } if (xresult instanceof XBoolean) { return ((XBoolean) xresult).bool() ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } if (xresult instanceof XNull) { return null; } if (xresult instanceof XString) { return new SimpleScalar(xresult.toString()); } if (xresult instanceof XNumber) { return new SimpleNumber(new Double(((XNumber) xresult).num())); } throw new TemplateModelException("Cannot deal with type: " + xresult.getClass().getName()); } catch (TransformerException te) { throw new TemplateModelException(te); } } private static PrefixResolver customPrefixResolver = new PrefixResolver() { public String getNamespaceForPrefix(String prefix, Node node) { return getNamespaceForPrefix(prefix); } public String getNamespaceForPrefix(String prefix) { if (prefix.equals(Template.DEFAULT_NAMESPACE_PREFIX)) { return Environment.getCurrentEnvironment().getDefaultNS(); } return Environment.getCurrentEnvironment().getNamespaceForPrefix(prefix); } public String getBaseIdentifier() { return null; } public boolean handlesNullPrefixes() { return false; } }; /** * Used for generating more intelligent error messages. */ private static boolean isNodeList(Object context) { if (context instanceof List) { List ls = (List) context; int ln = ls.size(); for (int i = 0; i < ln; i++) { if (!(ls.get(i) instanceof Node)) { return false; } } return true; } else { return false; } } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/DocumentModel.java0000644000175000017500000000775711723544470025550 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import org.w3c.dom.*; import freemarker.template.*; import freemarker.core.Environment; import freemarker.template.utility.StringUtil; /** * A class that wraps the root node of a parsed XML document, using * the W3C DOM API. */ class DocumentModel extends NodeModel implements TemplateHashModel { private ElementModel rootElement; DocumentModel(Document doc) { super(doc); } public String getNodeName() { return "@document"; } public TemplateModel get(String key) throws TemplateModelException { if (key.equals("*")) { return getRootElement(); } else if (key.equals("**")) { NodeList nl = ((Document)node).getElementsByTagName("*"); return new NodeListModel(nl, this); } else if (StringUtil.isXMLID(key)) { ElementModel em = (ElementModel) NodeModel.wrap(((Document) node).getDocumentElement()); if (em.matchesName(key, Environment.getCurrentEnvironment())) { return em; } else { return new NodeListModel(this); } } return super.get(key); } ElementModel getRootElement() { if (rootElement == null) { rootElement = (ElementModel) wrap(((Document) node).getDocumentElement()); } return rootElement; } public boolean isEmpty() { return false; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/PINodeModel.java0000644000175000017500000000604011723544471025071 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import org.w3c.dom.*; import freemarker.template.*; class PINodeModel extends NodeModel implements TemplateScalarModel { public PINodeModel(ProcessingInstruction pi) { super(pi); } public String getAsString() { return ((ProcessingInstruction) node).getData(); } public String getNodeName() { return "@pi$" + ((ProcessingInstruction) node).getTarget(); } public boolean isEmpty() { return true; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/SunInternalXalanXPathSupport.java0000644000175000017500000001653311723544470030571 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import freemarker.template.*; import freemarker.core.Environment; import org.w3c.dom.*; import org.w3c.dom.traversal.NodeIterator; import com.sun.org.apache.xpath.internal.*; import com.sun.org.apache.xpath.internal.objects.*; import com.sun.org.apache.xml.internal.utils.PrefixResolver; import java.util.List; import javax.xml.transform.TransformerException; /** * This is just the XalanXPathSupport class using the sun internal * package names */ class SunInternalXalanXPathSupport implements XPathSupport { private XPathContext xpathContext = new XPathContext(); /* I don't recommend Jaxen... private static final String ERRMSG_RECOMMEND_JAXEN = "(Note that there is no such restriction if you " + "configure FreeMarker to use Jaxen instead of Xalan.)"; */ private static final String ERRMSG_EMPTY_NODE_SET = "Cannot perform an XPath query against an empty node set."; /* " + ERRMSG_RECOMMEND_JAXEN;*/ synchronized public TemplateModel executeQuery(Object context, String xpathQuery) throws TemplateModelException { if (!(context instanceof Node)) { if (context != null) { if (isNodeList(context)) { int cnt = ((List) context).size(); if (cnt != 0) { throw new TemplateModelException( "Cannot perform an XPath query against a node set of " + cnt + " nodes. Expecting a single node."/* " + ERRMSG_RECOMMEND_JAXEN*/); } else { throw new TemplateModelException(ERRMSG_EMPTY_NODE_SET); } } else { throw new TemplateModelException( "Cannot perform an XPath query against a " + context.getClass().getName() + ". Expecting a single org.w3c.dom.Node."); } } else { throw new TemplateModelException(ERRMSG_EMPTY_NODE_SET); } } Node node = (Node) context; try { XPath xpath = new XPath(xpathQuery, null, customPrefixResolver, XPath.SELECT, null); int ctxtNode = xpathContext.getDTMHandleFromNode(node); XObject xresult = xpath.execute(xpathContext, ctxtNode, customPrefixResolver); if (xresult instanceof XNodeSet) { NodeListModel result = new NodeListModel(node); result.xpathSupport = this; NodeIterator nodeIterator = xresult.nodeset(); Node n; do { n = nodeIterator.nextNode(); if (n != null) { result.add(n); } } while (n != null); return result.size() == 1 ? result.get(0) : result; } if (xresult instanceof XBoolean) { return ((XBoolean) xresult).bool() ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } if (xresult instanceof XNull) { return null; } if (xresult instanceof XString) { return new SimpleScalar(xresult.toString()); } if (xresult instanceof XNumber) { return new SimpleNumber(new Double(((XNumber) xresult).num())); } throw new TemplateModelException("Cannot deal with type: " + xresult.getClass().getName()); } catch (TransformerException te) { throw new TemplateModelException(te); } } private static PrefixResolver customPrefixResolver = new PrefixResolver() { public String getNamespaceForPrefix(String prefix, Node node) { return getNamespaceForPrefix(prefix); } public String getNamespaceForPrefix(String prefix) { if (prefix.equals(Template.DEFAULT_NAMESPACE_PREFIX)) { return Environment.getCurrentEnvironment().getDefaultNS(); } return Environment.getCurrentEnvironment().getNamespaceForPrefix(prefix); } public String getBaseIdentifier() { return null; } public boolean handlesNullPrefixes() { return false; } }; /** * Used for generating more intelligent error messages. */ private static boolean isNodeList(Object context) { if (context instanceof List) { List ls = (List) context; int ln = ls.size(); for (int i = 0; i < ln; i++) { if (!(ls.get(i) instanceof Node)) { return false; } } return true; } else { return false; } } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/NodeOutputter.java0000644000175000017500000002600311723544472025615 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import freemarker.template.utility.StringUtil; import freemarker.template.Template; import freemarker.core.Environment; import java.util.*; import org.w3c.dom.*; class NodeOutputter { private Element contextNode; private Environment env; private String defaultNS; private boolean hasDefaultNS; private boolean explicitDefaultNSPrefix; private HashMap namespacesToPrefixLookup = new HashMap(); private String namespaceDecl; NodeOutputter(Node node) { if (node instanceof Element) { setContext((Element) node); } else if (node instanceof Attr) { setContext(((Attr) node).getOwnerElement()); } else if (node instanceof Document) { setContext(((Document) node).getDocumentElement()); } } private void setContext(Element contextNode) { this.contextNode = contextNode; this.env = Environment.getCurrentEnvironment(); this.defaultNS = env.getDefaultNS(); this.hasDefaultNS = defaultNS != null && defaultNS.length() >0; namespacesToPrefixLookup.put(null, ""); namespacesToPrefixLookup.put("", ""); buildPrefixLookup(contextNode); if (!explicitDefaultNSPrefix && hasDefaultNS) { namespacesToPrefixLookup.put(defaultNS, ""); } constructNamespaceDecl(); } private void buildPrefixLookup(Node n) { String nsURI = n.getNamespaceURI(); if (nsURI != null && nsURI.length() >0) { String prefix = env.getPrefixForNamespace(nsURI); namespacesToPrefixLookup.put(nsURI, prefix); } else if (hasDefaultNS && n.getNodeType() == Node.ELEMENT_NODE) { namespacesToPrefixLookup.put(defaultNS, Template.DEFAULT_NAMESPACE_PREFIX); explicitDefaultNSPrefix = true; } else if (n.getNodeType() == Node.ATTRIBUTE_NODE && hasDefaultNS && defaultNS.equals(nsURI)) { namespacesToPrefixLookup.put(defaultNS, Template.DEFAULT_NAMESPACE_PREFIX); explicitDefaultNSPrefix = true; } NodeList childNodes = n.getChildNodes(); for (int i = 0; i0) { buf.append(":"); buf.append(prefix); } buf.append("=\""); buf.append(nsURI); buf.append("\""); } this.namespaceDecl = buf.toString(); } private void outputQualifiedName(Node n, StringBuffer buf) { String nsURI = n.getNamespaceURI(); if (nsURI == null || nsURI.length() == 0) { buf.append(n.getNodeName()); } else { String prefix = (String) namespacesToPrefixLookup.get(nsURI); if (prefix == null) { //REVISIT! buf.append(n.getNodeName()); } else { if (prefix.length() > 0) { buf.append(prefix); buf.append(':'); } buf.append(n.getLocalName()); } } } void outputContent(Node n, StringBuffer buf) { switch(n.getNodeType()) { case Node.ATTRIBUTE_NODE: { if (((Attr) n).getSpecified()) { buf.append(' '); outputQualifiedName(n, buf); buf.append("=\"") .append(StringUtil.XMLEncQAttr(n.getNodeValue())) .append('"'); } break; } case Node.COMMENT_NODE: { buf.append(""); break; } case Node.DOCUMENT_NODE: { outputContent(n.getChildNodes(), buf); break; } case Node.DOCUMENT_TYPE_NODE: { buf.append("'); break; } case Node.ELEMENT_NODE: { buf.append('<'); outputQualifiedName(n, buf); if (n == contextNode) { buf.append(namespaceDecl); } outputContent(n.getAttributes(), buf); NodeList children = n.getChildNodes(); if (children.getLength() == 0) { buf.append(" />"); } else { buf.append('>'); outputContent(n.getChildNodes(), buf); buf.append("'); } break; } case Node.ENTITY_NODE: { outputContent(n.getChildNodes(), buf); break; } case Node.ENTITY_REFERENCE_NODE: { buf.append('&').append(n.getNodeName()).append(';'); break; } case Node.PROCESSING_INSTRUCTION_NODE: { buf.append(""); break; } /* case Node.CDATA_SECTION_NODE: { buf.append(""); break; }*/ case Node.CDATA_SECTION_NODE: case Node.TEXT_NODE: { buf.append(StringUtil.XMLEncNQG(n.getNodeValue())); break; } } } void outputContent(NodeList nodes, StringBuffer buf) { for(int i = 0; i < nodes.getLength(); ++i) { outputContent(nodes.item(i), buf); } } void outputContent(NamedNodeMap nodes, StringBuffer buf) { for(int i = 0; i < nodes.getLength(); ++i) { Node n = nodes.item(i); if (n.getNodeType() != Node.ATTRIBUTE_NODE || (!n.getNodeName().startsWith("xmlns:") && !n.getNodeName().equals("xmlns"))) { outputContent(n, buf); } } } String getOpeningTag(Element element) { StringBuffer buf = new StringBuffer(); buf.append('<'); outputQualifiedName(element, buf); buf.append(namespaceDecl); outputContent(element.getAttributes(), buf); buf.append('>'); return buf.toString(); } String getClosingTag(Element element) { StringBuffer buf = new StringBuffer(); buf.append("'); return buf.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/ElementModel.java0000644000175000017500000002073111723544470025346 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import org.w3c.dom.*; import freemarker.template.*; import freemarker.template.utility.StringUtil; import freemarker.core.Environment; class ElementModel extends NodeModel implements TemplateScalarModel { public ElementModel(Element element) { super(element); } public boolean isEmpty() { return false; } /** * An Element node supports various hash keys. * Any key that corresponds to the tag name of any child elements * returns a sequence of those elements. The special key "*" returns * all the element's direct children. * The "**" key return all the element's descendants in the order they * occur in the document. * Any key starting with '@' is taken to be the name of an element attribute. * The special key "@@" returns a hash of all the element's attributes. * The special key "/" returns the root document node associated with this element. */ public TemplateModel get(String key) throws TemplateModelException { if (key.equals("*")) { NodeListModel ns = new NodeListModel(this); TemplateSequenceModel children = getChildNodes(); for (int i=0;i < children.size();i++) { NodeModel child = (NodeModel) children.get(i); if (child.node.getNodeType() == Node.ELEMENT_NODE) { ns.add(child); } } return ns; } if (key.equals("**")) { Element elem = (Element) node; return new NodeListModel(elem.getElementsByTagName("*"), this); } if (key.startsWith("@")) { if (key.equals("@@") || key.equals("@*")) { return new NodeListModel(node.getAttributes(), this); } if (key.equals("@@start_tag")) { NodeOutputter nodeOutputter = new NodeOutputter(node); return new SimpleScalar(nodeOutputter.getOpeningTag((Element) node)); } if (key.equals("@@end_tag")) { NodeOutputter nodeOutputter = new NodeOutputter(node); return new SimpleScalar(nodeOutputter.getClosingTag((Element) node)); } if (key.equals("@@attributes_markup")) { StringBuffer buf = new StringBuffer(); NodeOutputter nu = new NodeOutputter(node); nu.outputContent(node.getAttributes(), buf); return new SimpleScalar(buf.toString().trim()); } if (StringUtil.isXMLID(key.substring(1))) { Attr att = getAttribute(key.substring(1), Environment.getCurrentEnvironment()); if (att == null) { return new NodeListModel(this); } return wrap(att); } } if (StringUtil.isXMLID(key)) { NodeListModel result = ((NodeListModel) getChildNodes()).filterByName(key); if (result.size() == 1) { return result.get(0); } return result; } return super.get(key); } public String getAsString() throws TemplateModelException { NodeList nl = node.getChildNodes(); String result = ""; for (int i = 0; i0) { prefix += ":"; } return prefix + nodeName; } private Attr getAttribute(String qname, Environment env) { Element element = (Element) node; Attr result = element.getAttributeNode(qname); if (result != null) return result; int colonIndex = qname.indexOf(':'); if (colonIndex >0) { String prefix = qname.substring(0, colonIndex); String uri; if (prefix.equals(Template.DEFAULT_NAMESPACE_PREFIX)) { uri = Environment.getCurrentEnvironment().getDefaultNS(); } else { uri = Environment.getCurrentEnvironment().getNamespaceForPrefix(prefix); } String localName = qname.substring(1+colonIndex); if (uri != null) { result = element.getAttributeNodeNS(uri, localName); } } return result; } boolean matchesName(String name, Environment env) { return StringUtil.matchesName(name, getNodeName(), getNodeNamespace(), env); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/JaxenXPathSupport.java0000644000175000017500000002432611723544470026407 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import freemarker.template.*; import freemarker.template.utility.Collections12; import freemarker.template.utility.UndeclaredThrowableException; import freemarker.cache.TemplateCache; import freemarker.core.CustomAttribute; import freemarker.core.Environment; import org.jaxen.*; import org.jaxen.dom.DocumentNavigator; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; /** * @author Jonathan Revusky * @version $Id: JaxenXPathSupport.java,v 1.30 2003/12/20 01:17:30 ddekany Exp $ */ class JaxenXPathSupport implements XPathSupport { private static final CustomAttribute cache = new CustomAttribute(CustomAttribute.SCOPE_TEMPLATE) { protected Object create() { return new HashMap(); } }; private final static ArrayList EMPTY_ARRAYLIST = new ArrayList(); public TemplateModel executeQuery(Object context, String xpathQuery) throws TemplateModelException { try { BaseXPath xpath; Map xpathCache = (Map)cache.get(); synchronized(xpathCache) { xpath = (BaseXPath) xpathCache.get(xpathQuery); if (xpath == null) { xpath = new BaseXPath(xpathQuery, fmDomNavigator); xpath.setNamespaceContext(customNamespaceContext); xpath.setFunctionContext(fmFunctionContext); xpath.setVariableContext(fmVariableContext); xpathCache.put(xpathQuery, xpath); } } List result = xpath.selectNodes(context != null ? context : EMPTY_ARRAYLIST); if (result.size() == 1) { return ObjectWrapper.DEFAULT_WRAPPER.wrap(result.get(0)); } NodeListModel nlm = new NodeListModel(result, null); nlm.xpathSupport = this; return nlm; } catch (UndeclaredThrowableException e) { Throwable t = e.getUndeclaredThrowable(); if(t instanceof TemplateModelException) { throw (TemplateModelException)t; } throw e; } catch (JaxenException je) { throw new TemplateModelException(je); } } static private final NamespaceContext customNamespaceContext = new NamespaceContext() { public String translateNamespacePrefixToUri(String prefix) { if (prefix.equals(Template.DEFAULT_NAMESPACE_PREFIX)) { return Environment.getCurrentEnvironment().getDefaultNS(); } return Environment.getCurrentEnvironment().getNamespaceForPrefix(prefix); } }; private static final VariableContext fmVariableContext = new VariableContext() { public Object getVariableValue(String namespaceURI, String prefix, String localName) throws UnresolvableException { try { TemplateModel model = Environment.getCurrentEnvironment().getVariable(localName); if(model == null) { throw new UnresolvableException("Variable " + localName + " not found."); } if(model instanceof TemplateScalarModel) { return ((TemplateScalarModel)model).getAsString(); } if(model instanceof TemplateNumberModel) { return ((TemplateNumberModel)model).getAsNumber(); } if(model instanceof TemplateDateModel) { return ((TemplateDateModel)model).getAsDate(); } if(model instanceof TemplateBooleanModel) { return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; } } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } throw new UnresolvableException("Variable " + localName + " is not a string, number, date, or boolean"); } }; private static final FunctionContext fmFunctionContext = new XPathFunctionContext() { public Function getFunction(String namespaceURI, String prefix, String localName) throws UnresolvableException { try { return super.getFunction(namespaceURI, prefix, localName); } catch(UnresolvableException e) { return super.getFunction(null, null, localName); } } }; private static final CustomAttribute cachedTree = new CustomAttribute(CustomAttribute.SCOPE_TEMPLATE); private static final Navigator fmDomNavigator = new DocumentNavigator() { public Object getDocument(String uri) throws FunctionCallException { try { Template raw = getTemplate(uri); Document doc = (Document)cachedTree.get(raw); if(doc == null) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = factory.newDocumentBuilder(); FmEntityResolver er = new FmEntityResolver(); builder.setEntityResolver(er); doc = builder.parse(createInputSource(null, raw)); // If the entity resolver got called 0 times, the document // is standalone, so we can safely cache it if(er.getCallCount() == 0) { cachedTree.set(doc, raw); } } return doc; } catch (Exception e) { throw new FunctionCallException("Failed to parse document for URI: " + uri, e); } } }; static Template getTemplate(String systemId) throws IOException { Environment env = Environment.getCurrentEnvironment(); String encoding = env.getTemplate().getEncoding(); if (encoding == null) { encoding = env.getConfiguration().getEncoding(env.getLocale()); } String templatePath = env.getTemplate().getName(); int lastSlash = templatePath.lastIndexOf('/'); templatePath = lastSlash == -1 ? "" : templatePath.substring(0, lastSlash + 1); systemId = TemplateCache.getFullTemplatePath(env, templatePath, systemId); Template raw = env.getConfiguration().getTemplate(systemId, env.getLocale(), encoding, false); return raw; } private static InputSource createInputSource(String publicId, Template raw) throws IOException, SAXException { StringWriter sw = new StringWriter(); try { raw.process(Collections12.EMPTY_MAP, sw); } catch(TemplateException e) { throw new SAXException(e); } InputSource is = new InputSource(); is.setPublicId(publicId); is.setSystemId(raw.getName()); is.setCharacterStream(new StringReader(sw.toString())); return is; } private static class FmEntityResolver implements EntityResolver { private int callCount = 0; public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { ++callCount; return createInputSource(publicId, getTemplate(systemId)); } int getCallCount() { return callCount; } }; } libfreemarker-java-2.3.19.orig/src/freemarker/ext/dom/AttributeNodeModel.java0000644000175000017500000000733411723544471026533 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.dom; import freemarker.template.*; import freemarker.core.Environment; import org.w3c.dom.*; class AttributeNodeModel extends NodeModel implements TemplateScalarModel { public AttributeNodeModel(Attr att) { super(att); } public String getAsString() { return ((Attr) node).getValue(); } public String getNodeName() { String result = node.getLocalName(); if (result == null || result.equals("")) { result = node.getNodeName(); } return result; } public boolean isEmpty() { return true; } String getQualifiedName() { String nsURI = node.getNamespaceURI(); if (nsURI == null || nsURI.equals("")) return node.getNodeName(); Environment env = Environment.getCurrentEnvironment(); String defaultNS = env.getDefaultNS(); String prefix = null; if (nsURI.equals(defaultNS)) { prefix = "D"; } else { prefix = env.getPrefixForNamespace(nsURI); } if (prefix == null) { return null; } return prefix + ":" + node.getLocalName(); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/0000755000175000017500000000000012164627123022144 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/JaxenNamespaces.java0000644000175000017500000000551111723544472026063 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import org.jaxen.NamespaceContext; class JaxenNamespaces extends Namespaces implements NamespaceContext { static final Factory FACTORY = new Factory() { public Namespaces create() { return new JaxenNamespaces(); } }; }libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/Navigator.java0000644000175000017500000002623711723544470024756 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import java.io.StringWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import org.jaxen.NamespaceContext; import freemarker.template.TemplateModelException; /** * @version $Id: Navigator.java,v 1.4 2003/01/31 11:39:17 szegedia Exp $ * @author Attila Szegedi */ abstract class Navigator { // Cache of already parsed XPath expressions private final Map xpathCache = new WeakHashMap(); // Operators this navigator defines private final Map operators = createOperatorMap(); private final NodeOperator attributeOperator = getOperator("_attributes"); private final NodeOperator childrenOperator = getOperator("_children"); NodeOperator getOperator(String key) { return (NodeOperator)operators.get(key); } NodeOperator getAttributeOperator() { return attributeOperator; } NodeOperator getChildrenOperator() { return childrenOperator; } abstract void getAsString(Object node, StringWriter sw) throws TemplateModelException; List applyXPath(List nodes, String xpathString, Object namespaces) throws TemplateModelException { XPathEx xpath = null; try { synchronized(xpathCache) { xpath = (XPathEx)xpathCache.get(xpathString); if (xpath == null) { xpath = createXPathEx(xpathString); xpathCache.put(xpathString, xpath); } } return xpath.selectNodes(nodes, (NamespaceContext)namespaces); } catch(Exception e) { throw new TemplateModelException("Could not evaulate XPath expression " + xpathString, e); } } interface XPathEx { List selectNodes(Object nodes, NamespaceContext namespaces) throws TemplateModelException; } abstract XPathEx createXPathEx(String xpathString) throws TemplateModelException; abstract void getChildren(Object node, String localName, String namespaceUri, List result); abstract void getAttributes(Object node, String localName, String namespaceUri, List result); abstract void getDescendants(Object node, List result); abstract Object getParent(Object node); abstract Object getDocument(Object node); abstract Object getDocumentType(Object node); private void getAncestors(Object node, List result) { for(;;) { Object parent = getParent(node); if(parent == null) { break; } result.add(parent); node = parent; } } abstract void getContent(Object node, List result); abstract String getText(Object node); abstract String getLocalName(Object node); abstract String getNamespacePrefix(Object node); String getQualifiedName(Object node) { String lname = getLocalName(node); if(lname == null) { return null; } String nsprefix = getNamespacePrefix(node); if(nsprefix == null || nsprefix.length() == 0) { return lname; } else { return nsprefix + ":" + lname; } } abstract String getType(Object node); abstract String getNamespaceUri(Object node); boolean equal(String s1, String s2) { return s1 == null ? s2 == null : s1.equals(s2); } private Map createOperatorMap() { Map map = new HashMap(); map.put("_attributes", new AttributesOp()); map.put("@*", map.get("_attributes")); map.put("_children", new ChildrenOp()); map.put("*", map.get("_children")); map.put("_descendantOrSelf", new DescendantOrSelfOp()); map.put("_descendant", new DescendantOp()); map.put("_document", new DocumentOp()); map.put("_doctype", new DocumentTypeOp()); map.put("_ancestor", new AncestorOp()); map.put("_ancestorOrSelf", new AncestorOrSelfOp()); map.put("_content", new ContentOp()); map.put("_name", new LocalNameOp()); map.put("_nsprefix", new NamespacePrefixOp()); map.put("_nsuri", new NamespaceUriOp()); map.put("_parent", new ParentOp()); map.put("_qname", new QualifiedNameOp()); map.put("_text", new TextOp()); map.put("_type", new TypeOp()); return map; } private class ChildrenOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { getChildren(node, localName, namespaceUri, result); } } private class AttributesOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { getAttributes(node, localName, namespaceUri, result); } } private class DescendantOrSelfOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { result.add(node); getDescendants(node, result); } } private class DescendantOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { getDescendants(node, result); } } private class AncestorOrSelfOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { result.add(node); getAncestors(node, result); } } private class AncestorOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { getAncestors(node, result); } } private class ParentOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { Object parent = getParent(node); if(parent != null) { result.add(parent); } } } private class DocumentOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { Object document = getDocument(node); if(document != null) { result.add(document); } } } private class DocumentTypeOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { Object documentType = getDocumentType(node); if(documentType != null) { result.add(documentType); } } } private class ContentOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { getContent(node, result); } } private class TextOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { String text = getText(node); if(text != null) { result.add(text); } } } private class LocalNameOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { String text = getLocalName(node); if(text != null) { result.add(text); } } } private class QualifiedNameOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { String qname = getQualifiedName(node); if(qname != null) { result.add(qname); } } } private class NamespacePrefixOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { String text = getNamespacePrefix(node); if(text != null) { result.add(text); } } } private class NamespaceUriOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { String text = getNamespaceUri(node); if(text != null) { result.add(text); } } } private class TypeOp implements NodeOperator { public void process(Object node, String localName, String namespaceUri, List result) { result.add(getType(node)); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/Dom4jNavigator.java0000644000175000017500000002241611723544470025647 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import java.io.StringWriter; import java.util.Iterator; import java.util.List; import freemarker.template.TemplateModelException; import org.dom4j.Attribute; import org.dom4j.Branch; import org.dom4j.Document; import org.dom4j.DocumentType; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.ProcessingInstruction; import org.dom4j.tree.DefaultAttribute; import org.jaxen.Context; import org.jaxen.NamespaceContext; import org.jaxen.dom4j.Dom4jXPath; /** * @version $Id: Dom4jNavigator.java,v 1.3 2003/01/31 11:39:17 szegedia Exp $ * @author Attila Szegedi */ class Dom4jNavigator extends Navigator { Dom4jNavigator() { } void getAsString(Object node, StringWriter sw) { sw.getBuffer().append(((Node)node).asXML()); } void getChildren(Object node, String localName, String namespaceUri, List result) { if(node instanceof Element) { Element e = (Element)node; if(localName == null) { result.addAll(e.elements()); } else { result.addAll(e.elements(e.getQName().getDocumentFactory().createQName(localName, "", namespaceUri))); } } else if(node instanceof Document) { Element root = ((Document)node).getRootElement(); if(localName == null || (equal(root.getName(), localName) && equal(root.getNamespaceURI(), namespaceUri))) { result.add(root); } } } void getAttributes(Object node, String localName, String namespaceUri, List result) { if(node instanceof Element) { Element e = (Element)node; if(localName == null) { result.addAll(e.attributes()); } else { Attribute attr = e.attribute(e.getQName().getDocumentFactory().createQName(localName, "", namespaceUri)); if(attr != null) { result.add(attr); } } } else if (node instanceof ProcessingInstruction) { ProcessingInstruction pi = (ProcessingInstruction)node; if ("target".equals(localName)) { result.add(new DefaultAttribute("target", pi.getTarget())); } else if ("data".equals(localName)) { result.add(new DefaultAttribute("data", pi.getText())); } else { result.add(new DefaultAttribute(localName, pi.getValue(localName))); } } else if (node instanceof DocumentType) { DocumentType doctype = (DocumentType)node; if ("publicId".equals(localName)) { result.add(new DefaultAttribute("publicId", doctype.getPublicID())); } else if ("systemId".equals(localName)) { result.add(new DefaultAttribute("systemId", doctype.getSystemID())); } else if ("elementName".equals(localName)) { result.add(new DefaultAttribute("elementName", doctype.getElementName())); } } } void getDescendants(Object node, List result) { if(node instanceof Branch) { getDescendants((Branch)node, result); } } private void getDescendants(Branch node, List result) { List content = node.content(); for (Iterator iter = content.iterator(); iter.hasNext();) { Node subnode = (Node) iter.next(); if(subnode instanceof Element) { result.add(subnode); getDescendants(subnode, result); } } } Object getParent(Object node) { return ((Node)node).getParent(); } Object getDocument(Object node) { return ((Node)node).getDocument(); } Object getDocumentType(Object node) { return node instanceof Document ? ((Document)node).getDocType() : null; } void getContent(Object node, List result) { if(node instanceof Branch) { result.addAll(((Branch)node).content()); } } String getText(Object node) { return ((Node)node).getText(); } String getLocalName(Object node) { return ((Node)node).getName(); } String getNamespacePrefix(Object node) { if(node instanceof Element) { return ((Element)node).getNamespacePrefix(); } if(node instanceof Attribute) { return ((Attribute)node).getNamespacePrefix(); } return null; } String getNamespaceUri(Object node) { if(node instanceof Element) { return ((Element)node).getNamespaceURI(); } if(node instanceof Attribute) { return ((Attribute)node).getNamespaceURI(); } return null; } String getType(Object node) { switch(((Node)node).getNodeType()) { case Node.ATTRIBUTE_NODE: { return "attribute"; } case Node.CDATA_SECTION_NODE: { return "cdata"; } case Node.COMMENT_NODE: { return "comment"; } case Node.DOCUMENT_NODE: { return "document"; } case Node.DOCUMENT_TYPE_NODE: { return "documentType"; } case Node.ELEMENT_NODE: { return "element"; } case Node.ENTITY_REFERENCE_NODE: { return "entityReference"; } case Node.NAMESPACE_NODE: { return "namespace"; } case Node.PROCESSING_INSTRUCTION_NODE: { return "processingInstruction"; } case Node.TEXT_NODE: { return "text"; } } return "unknown"; } XPathEx createXPathEx(String xpathString) throws TemplateModelException { try { return new Dom4jXPathEx(xpathString); } catch(Exception e) { throw new TemplateModelException(e); } } private static final class Dom4jXPathEx extends Dom4jXPath implements XPathEx { Dom4jXPathEx(String path) throws Exception { super(path); } public List selectNodes(Object object, NamespaceContext namespaces) throws TemplateModelException { Context context = getContext(object); context.getContextSupport().setNamespaceContext(namespaces); try { return selectNodesForContext(context); } catch(Exception e) { throw new TemplateModelException(e); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/Namespaces.java0000644000175000017500000001114511723544470025073 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import freemarker.template.TemplateMethodModel; import java.lang.String; import java.util.List; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateModelException; import java.util.HashMap; /** * @author Attila Szegedi * @version $Id: Namespaces.java,v 1.4 2003/10/13 11:57:50 szegedia Exp $ */ class Namespaces implements TemplateMethodModel, Cloneable { static final Factory FACTORY = new Factory() { public Namespaces create() { return new Namespaces(); } }; private HashMap namespaces; private boolean shared; Namespaces() { namespaces = new HashMap(); namespaces.put("", ""); namespaces.put("xml", "http://www.w3.org/XML/1998/namespace"); shared = false; } public Object clone() { try { Namespaces clone = (Namespaces)super.clone(); clone.namespaces = (HashMap)namespaces.clone(); clone.shared = false; return clone; } catch(CloneNotSupportedException e) { throw new Error(); // Cannot happen } } public String translateNamespacePrefixToUri(String prefix) { synchronized(namespaces) { return (String)namespaces.get(prefix); } } public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 2) { throw new TemplateModelException("_registerNamespace(prefix, uri) requires two arguments"); } registerNamespace((String)arguments.get(0), (String)arguments.get(1)); return TemplateScalarModel.EMPTY_STRING; } void registerNamespace(String prefix, String uri) { synchronized(namespaces) { namespaces.put(prefix, uri); } } void markShared() { if(!shared) { shared = true; } } boolean isShared() { return shared; } interface Factory { Namespaces create(); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/NodeListModel.java0000644000175000017500000006325711723544471025532 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import freemarker.log.Logger; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNodeModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.Collections12; /** *

A data model adapter for three widespread XML document object model * representations: W3C DOM, dom4j, and JDOM. The adapter automatically * recognizes the used XML object model and provides a unified interface for it * toward the template. The model provides access to all XML InfoSet features * of the XML document and includes XPath support if it has access to the XPath- * evaluator library Jaxen. The model's philosophy (which closely follows that * of XML InfoSet and XPath) is as follows: it always wraps a list of XML nodes * (the "nodelist"). The list can be empty, can have a single element, or can * have multiple elements. Every operation applied to the model is applied to * all nodes in its nodelist. You usually start with a single- element nodelist, * usually the root element node or the document node of the XML tree. * Additionally, the nodes can contain String objects as a result of certain * evaluations (getting the names of elements, values of attributes, etc.)

*

Implementation note: If you are using W3C DOM documents * built by the Crimson XML parser (or you are using the built-in JDK 1.4 XML * parser, which is essentially Crimson), make sure you call * setNamespaceAware(true) on the * javax.xml.parsers.DocumentBuilderFactory instance used for document * building even when your documents don't use XML namespaces. Failing to do so, * you will experience incorrect behavior when using the documents wrapped with * this model.

* * @deprecated Use {@link freemarker.ext.dom.NodeModel} instead. * @version $Id: NodeListModel.java,v 1.15 2004/01/06 17:06:43 szegedia Exp $ * @author Attila Szegedi */ public class NodeListModel implements TemplateHashModel, TemplateMethodModel, TemplateScalarModel, TemplateSequenceModel, TemplateNodeModel { private static final Logger logger = Logger.getLogger("freemarker.xml"); private static final Class DOM_NODE_CLASS = getClass("org.w3c.dom.Node"); private static final Class DOM4J_NODE_CLASS = getClass("org.dom4j.Node"); private static final Navigator DOM_NAVIGATOR = getNavigator("Dom"); private static final Navigator DOM4J_NAVIGATOR = getNavigator("Dom4j"); private static final Navigator JDOM_NAVIGATOR = getNavigator("Jdom"); private static final Namespaces.Factory NS_FACTORY = getNamespacesFactory(); // The navigator object that implements document model-specific behavior. private final Navigator navigator; // The contained nodes private final List nodes; // The namespaces object (potentially shared by multiple models) private Namespaces namespaces; /** * Creates a new NodeListModel, wrapping the passed nodes. * @param nodes you can pass it a single XML node from any supported * document model, or a Java collection containing any number of nodes. * Passing null is prohibited. To create an empty model, pass it an empty * collection. If a collection is passed, all passed nodes must belong to * the same XML object model, i.e. you can't mix JDOM and dom4j in a single * instance of NodeListModel. The model itself doesn't check for this condition, * as it can be time consuming, but will throw spurious * {@link ClassCastException}s when it encounters mixed objects. * @throws IllegalArgumentException if you pass null */ public NodeListModel(Object nodes) { Object node = nodes; if(nodes instanceof Collection) { this.nodes = new ArrayList((Collection)nodes); node = this.nodes.isEmpty() ? null : this.nodes.get(0); } else if(nodes != null) { this.nodes = Collections12.singletonList(nodes); } else { throw new IllegalArgumentException("nodes == null"); } if(DOM_NODE_CLASS != null && DOM_NODE_CLASS.isInstance(node)) { navigator = DOM_NAVIGATOR; } else if(DOM4J_NODE_CLASS != null && DOM4J_NODE_CLASS.isInstance(node)) { navigator = DOM4J_NAVIGATOR; } else { // Assume JDOM navigator = JDOM_NAVIGATOR; } namespaces = NS_FACTORY.create(); } private NodeListModel(Navigator navigator, List nodes, Namespaces namespaces) { this.navigator = navigator; this.nodes = nodes; this.namespaces = namespaces; } private NodeListModel deriveModel(List derivedNodes) { namespaces.markShared(); return new NodeListModel(navigator, derivedNodes, namespaces); } /** * Returns the number of nodes in this model's nodelist. * @see freemarker.template.TemplateSequenceModel#size() */ public int size() { return nodes.size(); } /** * Evaluates an XPath expression on XML nodes in this model. * @param arguments the arguments to the method invocation. Expectes exactly * one argument - the XPath expression. * @return a new NodeListModel with nodes selected by applying the XPath * expression to this model's nodelist. * @see freemarker.template.TemplateMethodModel#exec(List) */ public Object exec(List arguments) throws TemplateModelException { if(arguments.size() != 1) { throw new TemplateModelException( "Expecting exactly one argument - an XPath expression"); } return deriveModel(navigator.applyXPath(nodes, (String)arguments.get(0), namespaces)); } /** * Returns the string representation of the wrapped nodes. String objects in * the nodelist are rendered as-is (with no XML escaping applied). All other * nodes are rendered in the default XML serialization format ("plain XML"). * This makes the model quite suited for use as an XML-transformation tool. * @return the string representation of the wrapped nodes. String objects * in the nodelist are rendered as-is (with no XML escaping applied). All * other nodes are rendered in the default XML serialization format ("plain * XML"). * @see freemarker.template.TemplateScalarModel#getAsString() */ public String getAsString() throws TemplateModelException { StringWriter sw = new StringWriter(size() * 128); for (Iterator iter = nodes.iterator(); iter.hasNext();) { Object o = iter.next(); if(o instanceof String) { sw.write((String)o); } else { navigator.getAsString(o, sw); } } return sw.toString(); } /** * Selects a single node from this model's nodelist by its list index and * returns a new NodeListModel containing that single node. * @param index the ordinal number of the selected node * @see freemarker.template.TemplateSequenceModel#get(int) */ public TemplateModel get(int index) { return deriveModel(Collections12.singletonList(nodes.get(index))); } /** * Returns a new NodeListModel containing the nodes that result from applying * an operator to this model's nodes. * @param key the operator to apply to nodes. Available operators are: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Key nameEvaluates to
* or _childrenall direct element children of current nodes (non-recursive). * Applicable to element and document nodes.
@* or _attributesall attributes of current nodes. Applicable to elements only. *
@attributeNamenamed attributes of current nodes. Applicable to elements, * doctypes and processing instructions. On doctypes it supports * attributes publicId, systemId and * elementName. On processing instructions, it supports * attributes target and data, as well as any * other attribute name specified in data as * name="value" pair on dom4j or JDOM models. * The attribute nodes for doctype and processing instruction are * synthetic, and as such have no parent. Note, however that * @* does NOT operate on doctypes or processing * instructions.
_ancestorall ancestors up to root element (recursive) of current nodes. * Applicable to same node types as _parent.
_ancestorOrSelfall ancestors of current nodes plus current nodes. Applicable * to same node types as _parent.
_cnamethe canonical names of current nodes (namespace URI + local * name), one string per node (non-recursive). Applicable to * elements and attributes
_contentthe complete content of current nodes, including children * elements, text, entity references, and processing instructions * (non-recursive). Applicable to elements and documents.
_descendantall recursive descendant element children of current nodes. * Applicable to document and element nodes.
_descendantOrSelfall recursive descendant element children of current nodes * plus current nodes. Applicable to document and element nodes. *
_documentall documents the current nodes belong to. Applicable to all * nodes except text.
_doctypedoctypes of the current nodes. Applicable to document nodes * only.
_filterTypeis 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 can pass * as many string arguments as you want, each representing one of * the types to select: "attribute", "cdata", * "comment", "document", * "documentType", "element", * "entity", "entityReference", * "namespace", "processingInstruction", or * "text".
_namethe names of current nodes, one string per node * (non-recursive). Applicable to elements and attributes * (returns their local names), entity references, processing * instructions (returns its target), doctypes (returns its public * ID)
_nsprefixthe namespace prefixes of current nodes, one string per node * (non-recursive). Applicable to elements and attributes
_nsurithe namespace URIs of current nodes, one string per node * (non-recursive). Applicable to elements and attributes
_parentparent elements of current nodes. Applicable to element, * attribute, comment, entity, processing instruction.
_qnamethe qualified names of current nodes in * [namespacePrefix:]localName form, one string per node * (non-recursive). Applicable to elements and attributes
_registerNamespace(prefix, uri)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 * nodelist["prefix:localname"] or * nodelist["@prefix:localname"] 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.
_textthe 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 NOT * escaped.
_typeReturns a string describing the type of nodes, one * string per node. The returned values are "attribute", * "cdata", "comment", "document", * "documentType", "element", * "entity", "entityReference", * "namespace", "processingInstruction", * "text", or "unknown".
_uniquea 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 * _parent, _ancestor, _ancestorOrSelf, * and _document on a node list with multiple elements. * I.e. foo._children._parent 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 foo._children._parent._unique to eliminate * duplicates. Applicable to all node types.
any other keyelement children of current nodes with name matching the key. * This allows for convenience child traversal in * book.chapter.title style syntax. Applicable to document * and element nodes.
* @return a new NodeListModel containing the nodes that result from applying * the operator to this model's nodes. * @see freemarker.template.TemplateHashModel#get(String) */ public TemplateModel get(String key) throws TemplateModelException { // Try a built-in navigator operator NodeOperator op = navigator.getOperator(key); String localName = null; String namespaceUri = ""; // If not a nav op, then check for special keys. if(op == null && key.length() > 0 && key.charAt(0) == '_') { if(key.equals("_unique")) { return deriveModel(removeDuplicates(nodes)); } else if(key.equals("_filterType") || key.equals("_ftype")) { return new FilterByType(); } else if(key.equals("_registerNamespace")) { if(namespaces.isShared()) { namespaces = (Namespaces)namespaces.clone(); } } } // Last, do a named child element or attribute lookup if(op == null) { int colon = key.indexOf(':'); if(colon == -1) { // No namespace prefix specified localName = key; } else { // Namespace prefix specified localName = key.substring(colon + 1); String prefix = key.substring(0, colon); namespaceUri = namespaces.translateNamespacePrefixToUri(prefix); if(namespaceUri == null) { throw new TemplateModelException("Namespace prefix " + prefix + " is not registered."); } } if(localName.charAt(0) == '@') { op = navigator.getAttributeOperator(); localName = localName.substring(1); } else { op = navigator.getChildrenOperator(); } } List result = new ArrayList(); for (Iterator iter = nodes.iterator(); iter.hasNext();) { try { op.process(iter.next(), localName, namespaceUri, result); } catch(RuntimeException e) { throw new TemplateModelException(e); } } return deriveModel(result); } /** * Returns true if this NodeListModel contains no nodes. * @see freemarker.template.TemplateHashModel#isEmpty() */ public boolean isEmpty() { return nodes.isEmpty(); } /** * Registers a namespace prefix-URI pair for subsequent use in {@link * #get(String)} as well as for use in XPath expressions. * @param prefix the namespace prefix to use for the namespace * @param uri the namespace URI that identifies the namespace. */ public void registerNamespace(String prefix, String uri) { if(namespaces.isShared()) { namespaces = (Namespaces)namespaces.clone(); } namespaces.registerNamespace(prefix, uri); } private class FilterByType implements TemplateMethodModel { public Object exec(List arguments) { List filteredNodes = new ArrayList(); for (Iterator iter = arguments.iterator(); iter.hasNext();) { Object node = iter.next(); if(arguments.contains(navigator.getType(node))) { filteredNodes.add(node); } } return deriveModel(filteredNodes); } } private static final List removeDuplicates(List list) { int s = list.size(); ArrayList ulist = new ArrayList(s); Set set = new HashSet(s * 4 / 3, .75f); Iterator it = list.iterator(); while (it.hasNext()) { Object o = it.next(); if (set.add(o)) { ulist.add(o); } } return ulist; } private static Class getClass(String className) { try { return ClassUtil.forName(className); } catch(Exception e) { if(logger.isDebugEnabled()) { logger.debug("Couldn't load class " + className, e); } return null; } } private static Namespaces.Factory getNamespacesFactory() { Namespaces.Factory factory = getNamespacesFactory("JaxenNamespaces"); if(factory == null) { factory = getNamespacesFactory("Namespaces"); } return factory; } private static Namespaces.Factory getNamespacesFactory(String clazz) { try { return (Namespaces.Factory) ClassUtil.forName("freemarker.ext.xml." + clazz) .getDeclaredField("FACTORY").get(null); } catch(Throwable t) { if(logger.isDebugEnabled()) { logger.debug("Could not load " + clazz, t); } return null; } } private static Navigator getNavigator(String navType) { try { Navigator nav = (Navigator) ClassUtil.forName("freemarker.ext.xml." + navType + "Navigator") .getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {}); return nav; } catch(Throwable t) { if(logger.isDebugEnabled()) { logger.debug("Could not load navigator for " + navType, t); } return null; } } public TemplateSequenceModel getChildNodes() throws TemplateModelException { return (TemplateSequenceModel)get("_content"); } public String getNodeName() throws TemplateModelException { return getUniqueText((NodeListModel)get("_name"), "name"); } public String getNodeNamespace() throws TemplateModelException { return getUniqueText((NodeListModel)get("_nsuri"), "namespace"); } public String getNodeType() throws TemplateModelException { return getUniqueText((NodeListModel)get("_type"), "type"); } public TemplateNodeModel getParentNode() throws TemplateModelException { return (TemplateNodeModel)get("_parent"); } 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 if there's already a text and they differ, start // accumulating them for an error message else 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); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/NodeOperator.java0000644000175000017500000000546211723544467025430 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import java.util.List; /** * @version $Id: NodeOperator.java,v 1.1 2003/01/22 23:05:55 szegedia Exp $ * @author Attila Szegedi */ interface NodeOperator { void process(Object node, String localName, String namespaceUri, List result); } libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/DomNavigator.java0000644000175000017500000003112311723544470025404 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import java.io.StringWriter; import java.util.List; import org.jaxen.Context; import org.jaxen.NamespaceContext; import org.jaxen.dom.DOMXPath; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import freemarker.template.TemplateModelException; import freemarker.template.utility.StringUtil; /** * @version $Id: DomNavigator.java,v 1.8 2003/09/02 09:54:59 szegedia Exp $ * @author Attila Szegedi */ class DomNavigator extends Navigator { DomNavigator() { } void getAsString(Object node, StringWriter sw) { outputContent((Node)node, sw.getBuffer()); } private void outputContent(Node n, StringBuffer buf) { switch(n.getNodeType()) { case Node.ATTRIBUTE_NODE: { buf.append(' ') .append(getQualifiedName(n)) .append("=\"") .append(StringUtil.XMLEncNA(n.getNodeValue())) // XmlEncNA for HTML compatibility .append('"'); break; } case Node.CDATA_SECTION_NODE: { buf.append(""); break; } case Node.COMMENT_NODE: { buf.append(""); break; } case Node.DOCUMENT_NODE: { outputContent(n.getChildNodes(), buf); break; } case Node.DOCUMENT_TYPE_NODE: { buf.append("'); break; } case Node.ELEMENT_NODE: { buf.append('<').append(getQualifiedName(n)); outputContent(n.getAttributes(), buf); buf.append('>'); outputContent(n.getChildNodes(), buf); buf.append("'); break; } case Node.ENTITY_NODE: { outputContent(n.getChildNodes(), buf); break; } case Node.ENTITY_REFERENCE_NODE: { buf.append('&').append(n.getNodeName()).append(';'); break; } case Node.PROCESSING_INSTRUCTION_NODE: { buf.append(""); break; } case Node.TEXT_NODE: { buf.append(StringUtil.XMLEncNQG(n.getNodeValue())); break; } } } private void outputContent(NodeList nodes, StringBuffer buf) { for(int i = 0; i < nodes.getLength(); ++i) { outputContent(nodes.item(i), buf); } } private void outputContent(NamedNodeMap nodes, StringBuffer buf) { for(int i = 0; i < nodes.getLength(); ++i) { outputContent(nodes.item(i), buf); } } void getChildren(Object node, String localName, String namespaceUri, List result) { if("".equals(namespaceUri)) { namespaceUri = null; } NodeList children = ((Node)node).getChildNodes(); for(int i = 0; i < children.getLength(); ++i) { Node subnode = children.item(i); // IMO, we should get the text nodes as well -- will discuss. if(subnode.getNodeType() == Node.ELEMENT_NODE || subnode.getNodeType() == Node.TEXT_NODE) { if(localName == null || (equal(subnode.getNodeName(), localName) && equal(subnode.getNamespaceURI(), namespaceUri))) { result.add(subnode); } } } } void getAttributes(Object node, String localName, String namespaceUri, List result) { if(node instanceof Element) { Element e = (Element)node; if(localName == null) { NamedNodeMap atts = e.getAttributes(); for(int i = 0; i < atts.getLength(); ++i) { result.add(atts.item(i)); } } else { if("".equals(namespaceUri)) { namespaceUri = null; } Attr attr = e.getAttributeNodeNS(namespaceUri, localName); if(attr != null) { result.add(attr); } } } else if (node instanceof ProcessingInstruction) { ProcessingInstruction pi = (ProcessingInstruction)node; if ("target".equals(localName)) { result.add(createAttribute(pi, "target", pi.getTarget())); } else if ("data".equals(localName)) { result.add(createAttribute(pi, "data", pi.getData())); } else { // TODO: DOM has no facility for parsing data into // name-value pairs... ; } } else if (node instanceof DocumentType) { DocumentType doctype = (DocumentType)node; if ("publicId".equals(localName)) { result.add(createAttribute(doctype, "publicId", doctype.getPublicId())); } else if ("systemId".equals(localName)) { result.add(createAttribute(doctype, "systemId", doctype.getSystemId())); } else if ("elementName".equals(localName)) { result.add(createAttribute(doctype, "elementName", doctype.getNodeName())); } } } private Attr createAttribute(Node node, String name, String value) { Attr attr = node.getOwnerDocument().createAttribute(name); attr.setNodeValue(value); return attr; } void getDescendants(Object node, List result) { NodeList children = ((Node)node).getChildNodes(); for(int i = 0; i < children.getLength(); ++i) { Node subnode = children.item(i); if(subnode.getNodeType() == Node.ELEMENT_NODE) { result.add(subnode); getDescendants(subnode, result); } } } Object getParent(Object node) { return ((Node)node).getParentNode(); } Object getDocument(Object node) { return ((Node)node).getOwnerDocument(); } Object getDocumentType(Object node) { return node instanceof Document ? ((Document)node).getDoctype() : null; } void getContent(Object node, List result) { NodeList children = ((Node)node).getChildNodes(); for(int i = 0; i < children.getLength(); ++i) { result.add(children.item(i)); } } String getText(Object node) { StringBuffer buf = new StringBuffer(); if(node instanceof Element) { NodeList children = ((Node)node).getChildNodes(); for(int i = 0; i < children.getLength(); ++i) { Node child = children.item(i); if(child instanceof Text) { buf.append(child.getNodeValue()); } } return buf.toString(); } else { return ((Node)node).getNodeValue(); } } String getLocalName(Object node) { return ((Node)node).getNodeName(); } String getNamespacePrefix(Object node) { return ((Node)node).getPrefix(); } String getNamespaceUri(Object node) { return ((Node)node).getNamespaceURI(); } String getType(Object node) { switch(((Node)node).getNodeType()) { case Node.ATTRIBUTE_NODE: { return "attribute"; } case Node.CDATA_SECTION_NODE: { return "cdata"; } case Node.COMMENT_NODE: { return "comment"; } case Node.DOCUMENT_NODE: { return "document"; } case Node.DOCUMENT_TYPE_NODE: { return "documentType"; } case Node.ELEMENT_NODE: { return "element"; } case Node.ENTITY_NODE: { return "entity"; } case Node.ENTITY_REFERENCE_NODE: { return "entityReference"; } case Node.PROCESSING_INSTRUCTION_NODE: { return "processingInstruction"; } case Node.TEXT_NODE: { return "text"; } } return "unknown"; } XPathEx createXPathEx(String xpathString) throws TemplateModelException { try { return new DomXPathEx(xpathString); } catch(Exception e) { throw new TemplateModelException(e); } } private static final class DomXPathEx extends DOMXPath implements XPathEx { DomXPathEx(String path) throws Exception { super(path); } public List selectNodes(Object object, NamespaceContext namespaces) throws TemplateModelException { Context context = getContext(object); context.getContextSupport().setNamespaceContext(namespaces); try { return selectNodesForContext(context); } catch(Exception e) { throw new TemplateModelException(e); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/JdomNavigator.java0000644000175000017500000003231611723544471025564 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.xml; import java.io.IOException; import java.io.StringWriter; import java.util.Iterator; import java.util.List; import freemarker.template.TemplateModelException; import org.jaxen.Context; import org.jaxen.NamespaceContext; import org.jaxen.jdom.JDOMXPath; import org.jdom.Element; import org.jdom.Attribute; import org.jdom.CDATA; import org.jdom.Comment; import org.jdom.DocType; import org.jdom.Document; import org.jdom.EntityRef; import org.jdom.Namespace; import org.jdom.ProcessingInstruction; import org.jdom.Text; import org.jdom.output.XMLOutputter; /** * @version $Id: JdomNavigator.java,v 1.3.4.2 2006/11/14 10:42:54 szegedia Exp $ * @author Attila Szegedi */ class JdomNavigator extends Navigator { private static final XMLOutputter OUTPUT = new XMLOutputter(); JdomNavigator() { } void getAsString(Object node, StringWriter sw) throws TemplateModelException { try { if (node instanceof Element) { OUTPUT.output((Element)node, sw); } else if (node instanceof Attribute) { Attribute attribute = (Attribute)node; sw.write(" "); sw.write(attribute.getQualifiedName()); sw.write("=\""); sw.write(OUTPUT.escapeAttributeEntities(attribute.getValue())); sw.write("\""); } else if (node instanceof Text) { OUTPUT.output((Text)node, sw); } else if (node instanceof Document) { OUTPUT.output((Document)node, sw); } else if (node instanceof ProcessingInstruction) { OUTPUT.output((ProcessingInstruction)node, sw); } else if (node instanceof Comment) { OUTPUT.output((Comment)node, sw); } else if (node instanceof CDATA) { OUTPUT.output((CDATA)node, sw); } else if (node instanceof DocType) { OUTPUT.output((DocType)node, sw); } else if (node instanceof EntityRef) { OUTPUT.output((EntityRef)node, sw); } else { throw new TemplateModelException(node.getClass().getName() + " is not a core JDOM class"); } } catch(IOException e) { throw new TemplateModelException(e); } } void getChildren(Object node, String localName, String namespaceUri, List result) { if(node instanceof Element) { Element e = (Element)node; if(localName == null) { result.addAll(e.getChildren()); } else { result.addAll(e.getChildren(localName, Namespace.getNamespace("", namespaceUri))); } } else if(node instanceof Document) { Element root = ((Document)node).getRootElement(); if(localName == null || (equal(root.getName(), localName) && equal(root.getNamespaceURI(), namespaceUri))) { result.add(root); } } } void getAttributes(Object node, String localName, String namespaceUri, List result) { if(node instanceof Element) { Element e = (Element)node; if(localName == null) { result.addAll(e.getAttributes()); } else { Attribute attr = e.getAttribute(localName, Namespace.getNamespace("", namespaceUri)); if(attr != null) { result.add(attr); } } } else if (node instanceof ProcessingInstruction) { ProcessingInstruction pi = (ProcessingInstruction)node; if ("target".equals(localName)) { result.add(new Attribute("target", pi.getTarget())); } else if ("data".equals(localName)) { result.add(new Attribute("data", pi.getData())); } else { result.add(new Attribute(localName, pi.getValue(localName))); } } else if (node instanceof DocType) { DocType doctype = (DocType)node; if ("publicId".equals(localName)) { result.add(new Attribute("publicId", doctype.getPublicID())); } else if ("systemId".equals(localName)) { result.add(new Attribute("systemId", doctype.getSystemID())); } else if ("elementName".equals(localName)) { result.add(new Attribute("elementName", doctype.getElementName())); } } } void getDescendants(Object node, List result) { if(node instanceof Document) { Element root = ((Document)node).getRootElement(); result.add(root); getDescendants(root, result); } else if(node instanceof Element) { getDescendants((Element)node, result); } } private void getDescendants(Element node, List result) { for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) { Element subnode = (Element)iter.next(); result.add(subnode); getDescendants(subnode, result); } } Object getParent(Object node) { if (node instanceof Element) { return((Element)node).getParent(); } if (node instanceof Attribute) { return((Attribute)node).getParent(); } if (node instanceof Text) { return((Text)node).getParent(); } if (node instanceof ProcessingInstruction) { return((ProcessingInstruction)node).getParent(); } if (node instanceof Comment) { return((Comment)node).getParent(); } if (node instanceof EntityRef) { return((EntityRef)node).getParent(); } return null; } Object getDocument(Object node) { if (node instanceof Element) { return ((Element)node).getDocument(); } else if (node instanceof Attribute) { Element parent = ((Attribute)node).getParent(); return parent == null ? null : parent.getDocument(); } else if (node instanceof Text) { Element parent = ((Text)node).getParent(); return parent == null ? null : parent.getDocument(); } else if (node instanceof Document) return node; else if (node instanceof ProcessingInstruction) { return ((ProcessingInstruction)node).getDocument(); } else if (node instanceof EntityRef) { return ((EntityRef)node).getDocument(); } else if (node instanceof Comment) { return ((Comment)node).getDocument(); } return null; } Object getDocumentType(Object node) { return node instanceof Document ? ((Document)node).getDocType() : null; } void getContent(Object node, List result) { if (node instanceof Element) result.addAll(((Element)node).getContent()); else if (node instanceof Document) result.addAll(((Document)node).getContent()); } String getText(Object node) { if (node instanceof Element) { return ((Element)node).getTextTrim(); } if (node instanceof Attribute) { return ((Attribute)node).getValue(); } if (node instanceof CDATA) { return ((CDATA)node).getText(); } if (node instanceof Comment) { return ((Comment)node).getText(); } if (node instanceof ProcessingInstruction) { return ((ProcessingInstruction)node).getData(); } return null; } String getLocalName(Object node) { if (node instanceof Element) { return ((Element)node).getName(); } if (node instanceof Attribute) { return ((Attribute)node).getName(); } if (node instanceof EntityRef) { return ((EntityRef)node).getName(); } if (node instanceof ProcessingInstruction) { return ((ProcessingInstruction)node).getTarget(); } if (node instanceof DocType) { return ((DocType)node).getElementName(); } return null; } String getNamespacePrefix(Object node) { if(node instanceof Element) { return ((Element)node).getNamespacePrefix(); } if(node instanceof Attribute) { return ((Attribute)node).getNamespacePrefix(); } return null; } String getNamespaceUri(Object node) { if(node instanceof Element) { return ((Element)node).getNamespaceURI(); } if(node instanceof Attribute) { return ((Attribute)node).getNamespaceURI(); } return null; } String getType(Object node) { if(node instanceof Attribute) { return "attribute"; } if(node instanceof CDATA) { return "cdata"; } if(node instanceof Comment) { return "comment"; } if(node instanceof Document) { return "document"; } if(node instanceof DocType) { return "documentType"; } if(node instanceof Element) { return "element"; } if(node instanceof EntityRef) { return "entityReference"; } if(node instanceof Namespace) { return "namespace"; } if(node instanceof ProcessingInstruction) { return "processingInstruction"; } if(node instanceof Text) { return "text"; } return "unknown"; } XPathEx createXPathEx(String xpathString) throws TemplateModelException { try { return new JDOMXPathEx(xpathString); } catch(Exception e) { throw new TemplateModelException(e); } } private static final class JDOMXPathEx extends JDOMXPath implements XPathEx { JDOMXPathEx(String path) throws Exception { super(path); } public List selectNodes(Object object, NamespaceContext namespaces) throws TemplateModelException { Context context = getContext(object); context.getContextSupport().setNamespaceContext(namespaces); try { return selectNodesForContext(context); } catch(Exception e) { throw new TemplateModelException(e); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/xml/package.html0000644000175000017500000000042311723544471024430 0ustar ebourgebourg

Provides data model adapter for DOM, dom4j and JDOM; three widely used XML document object models. Supports outputting of transformed XML documents, various node traversals, as well as full XPath support.

libfreemarker-java-2.3.19.orig/src/freemarker/ext/ant/0000755000175000017500000000000012164627123022126 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/ant/UnlinkedJythonOperations.java0000644000175000017500000000574411723544467030025 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.ant; import java.io.File; import java.util.Map; import org.apache.tools.ant.BuildException; /** * This is an interface to do Jython operations, which has no dependecy on * Jython classes (hence "unlinked"). * * @see JythonAntTask */ interface UnlinkedJythonOperations { void execute(String script, Map variables) throws BuildException; void execute(File file, Map variables) throws BuildException; } libfreemarker-java-2.3.19.orig/src/freemarker/ext/ant/UnlinkedJythonOperationsImpl.java0000644000175000017500000000721211723544472030633 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.ant; import java.io.*; import java.util.Iterator; import java.util.Map; import org.apache.tools.ant.BuildException; import org.python.util.PythonInterpreter; /** * Used internally, public for technical reasons only. */ public class UnlinkedJythonOperationsImpl implements UnlinkedJythonOperations { public void execute(String script, Map vars) throws BuildException { PythonInterpreter pi = createInterpreter(vars); pi.exec(script); } public void execute(File file, Map vars) throws BuildException { PythonInterpreter pi = createInterpreter(vars); try { pi.execfile(file.getCanonicalPath()); } catch (IOException e) { throw new BuildException(e); } } private PythonInterpreter createInterpreter(Map vars) { PythonInterpreter pi = new PythonInterpreter(); Iterator it = vars.entrySet().iterator(); while (it.hasNext()) { Map.Entry ent = (Map.Entry) it.next(); pi.set((String) ent.getKey(), ent.getValue()); } return pi; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/ant/FreemarkerXmlTask.java0000644000175000017500000006217211723544470026373 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.ant; import java.io.*; import java.util.*; import org.w3c.dom.*; import org.xml.sax.SAXParseException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.MatchingTask; import freemarker.ext.xml.NodeListModel; import freemarker.ext.dom.NodeModel; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.SecurityUtilities; import freemarker.template.*; /** *

This is an Ant task for transforming * XML documents using FreeMarker templates. It uses the adapter class * {@link NodeListModel}. It will read a set of XML documents, and pass them to * the template for processing, building the corresponding output files in the * destination directory.

*

It makes the following variables available to the template in the data model:

*
    *
  • document: Deprecated! The DOM tree of the currently processed XML file wrapped with the legacy {@link freemarker.ext.xml.NodeListModel}. For new projects you should use the .node instead, which initially contains the DOM Document wrapped with {@link freemarker.ext.dom.NodeModel}.
  • *
  • properties: a {@link freemarker.template.SimpleHash} containing * properties of the project that executes the task
  • *
  • userProperties: a {@link freemarker.template.SimpleHash} containing * user properties of the project that executes the task
  • *
  • project: the DOM tree of the XML file specified by the * projectfile. It will not be available if you didn't specify the * projectfile attribute.
  • *
  • further custom models can be instantiated and made available to the * templates using the models attribute.
  • *
*

It supports the following attributes:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
AttributeDescriptionRequired
basedirlocation of the XML files. Defaults to the project's * basedir.No
destdirlocation to store the generated files.Yes
includescomma-separated list of patterns of files that must be * included; all files are included when omitted.No
includesfilethe name of a file that contains * include patterns.No
excludescomma-separated list of patterns of files that must be * excluded; no files (except default excludes) are excluded when omitted.No
excludesfilethe name of a file that contains * exclude patterns.No
defaultexcludesindicates whether default excludes should be used * (yes | no); default excludes are used when omitted.No
extensionextension of generated files. Defaults to .html.No
templatename of the FreeMarker template file that will be * applied by default to XML filesNo
templateDirlocation of the FreeMarker template(s) to be used, defaults * to the project's baseDirNo
projectfilepath to the project file. The poject file must be an XML file. * If omitted, it will not be available to templates No
incrementalindicates whether all files should be regenerated (no), or * only those that are older than the XML file, the template file, or the * project file (yes). Defaults to yes. No
encodingThe encoding of the output files. Defaults to platform * default encoding.No
templateEncodingThe encoding of the template files. Defaults to platform * default encoding.No
validationWhether to validate the XML input. Defaults to off.No
modelsA list of [name=]className pairs separated by spaces, * commas, or semicolons that specifies further models that should be * available to templates. If name is omitted, the unqualified class name * is used as the name. Every class that is specified must implement the * TemplateModel interface and have a no-args constructor.No
* *

It supports the following nesed elements:

* * * * * * * * * * * * * * * * *
ElementDescriptionRequired
prepareModel * This element executes Jython script before the processing of each XML * files, that you can use to modify the data model. * You either enter the Jython script directly nested into this * element, or specify a Jython script file with the file * attribute. * The following variables are added to the Jython runtime's local * namespace before the script is invoked: *
    *
  • model: The data model as java.util.HashMap. * You can read and modify the data model with this variable. *
  • doc: The XML document as org.w3c.dom.Document. *
  • project: The project document (if used) as * org.w3c.dom.Document. *
* If this element is used, Jython classes (tried with Jython 2.1) * must be available. *
No
prepareEnvironmentThis element executes Jython script before the processing * of each XML files, that you can use to modify the freemarker environment * ({@link freemarker.core.Environment}). The script is executed after the * prepareModel element. The accessible Jython variables are the * same as with the prepareModel element, except that there is no * model variable, but there is env variable, which is * the FreeMarker environment ({@link freemarker.core.Environment}). * If this element is used, Jython classes (tried with Jython 2.1) * must be available. * No
* * @author Attila Szegedi * @author Jonathan Revusky, jon@revusky.com * @deprecated FMPP is a more complete solution. * @version $Id: FreemarkerXmlTask.java,v 1.58.2.1 2006/04/26 11:07:58 revusky Exp $ */ public class FreemarkerXmlTask extends MatchingTask { private JythonAntTask prepareModel; private JythonAntTask prepareEnvironment; private final DocumentBuilderFactory builderFactory; private DocumentBuilder builder; /** the {@link Configuration} used by this task. */ private Configuration cfg = new Configuration(); /** the destination directory */ private File destDir; /** the base directory */ private File baseDir; //Where the templates live private File templateDir; /** the template= attribute */ private String templateName; /** The template in its parsed form */ private Template parsedTemplate; /** last modified of the template sheet */ private long templateFileLastModified = 0; /** the projectFile= attribute */ private String projectAttribute = null; private File projectFile = null; /** The DOM tree of the project wrapped into FreeMarker TemplateModel */ private TemplateModel projectTemplate; // The DOM tree wrapped using the freemarker.ext.dom wrapping. private TemplateNodeModel projectNode; private TemplateModel propertiesTemplate; private TemplateModel userPropertiesTemplate; /** last modified of the project file if it exists */ private long projectFileLastModified = 0; /** check the last modified date on files. defaults to true */ private boolean incremental = true; /** the default output extension is .html */ private String extension = ".html"; private String encoding = SecurityUtilities.getSystemProperty("file.encoding"); private String templateEncoding = encoding; private boolean validation = false; private String models = ""; private final Map modelsMap = new HashMap(); /** * Constructor creates the SAXBuilder. */ public FreemarkerXmlTask() { builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); } /** * Set the base directory. Defaults to . */ public void setBasedir(File dir) { baseDir = dir; } /** * Set the destination directory into which the generated * files should be copied to * @param dir the name of the destination directory */ public void setDestdir(File dir) { destDir = dir; } /** * Set the output file extension. .html by default. */ public void setExtension(String extension) { this.extension = extension; } public void setTemplate(String templateName) { this.templateName = templateName; } public void setTemplateDir(File templateDir) throws BuildException { this.templateDir = templateDir; try { cfg.setDirectoryForTemplateLoading(templateDir); } catch (Exception e) { throw new BuildException(e); } } /** * Set the path to the project XML file */ public void setProjectfile(String projectAttribute) { this.projectAttribute = projectAttribute; } /** * Turn on/off incremental processing. On by default */ public void setIncremental(String incremental) { this.incremental = !(incremental.equalsIgnoreCase("false") || incremental.equalsIgnoreCase("no") || incremental.equalsIgnoreCase("off")); } /** * Set encoding for generated files. Defaults to platform default encoding. */ public void setEncoding(String encoding) { this.encoding = encoding; } public void setTemplateEncoding(String inputEncoding) { this.templateEncoding = inputEncoding; } /** * Sets whether to validate the XML input. */ public void setValidation(boolean validation) { this.validation = validation; } public void setModels(String models) { this.models = models; } public void execute() throws BuildException { DirectoryScanner scanner; String[] list; if (baseDir == null) { baseDir = getProject().getBaseDir(); } if (destDir == null ) { String msg = "destdir attribute must be set!"; throw new BuildException(msg, getLocation()); } File templateFile = null; if (templateDir == null) { if (templateName != null) { templateFile = new File(templateName); if (!templateFile.isAbsolute()) { templateFile = new File(getProject().getBaseDir(), templateName); } templateDir = templateFile.getParentFile(); templateName = templateFile.getName(); } else { templateDir = baseDir; } setTemplateDir(templateDir); } else if (templateName != null) { if (new File(templateName).isAbsolute()) { throw new BuildException("Do not specify an absolute location for the template as well as a templateDir"); } templateFile = new File(templateDir, templateName); } if (templateFile != null) { templateFileLastModified = templateFile.lastModified(); } try { if (templateName != null) { parsedTemplate = cfg.getTemplate(templateName, templateEncoding); } } catch (IOException ioe) { throw new BuildException(ioe.toString()); } // get the last modification of the template log("Transforming into: " + destDir.getAbsolutePath(), Project.MSG_INFO); // projectFile relative to baseDir if (projectAttribute != null && projectAttribute.length() > 0) { projectFile = new File(baseDir, projectAttribute); if (projectFile.isFile()) projectFileLastModified = projectFile.lastModified(); else { log ("Project file is defined, but could not be located: " + projectFile.getAbsolutePath(), Project.MSG_INFO ); projectFile = null; } } generateModels(); // find the files/directories scanner = getDirectoryScanner(baseDir); propertiesTemplate = wrapMap(project.getProperties()); userPropertiesTemplate = wrapMap(project.getUserProperties()); builderFactory.setValidating(validation); try { builder = builderFactory.newDocumentBuilder(); } catch(ParserConfigurationException e) { throw new BuildException("Could not create document builder", e, getLocation()); } // get a list of files to work on list = scanner.getIncludedFiles(); for (int i = 0;i < list.length; ++i) { process(baseDir, list[i], destDir); } } public void addConfiguredJython(JythonAntTask jythonAntTask) { this.prepareEnvironment = jythonAntTask; } public void addConfiguredPrepareModel(JythonAntTask prepareModel) { this.prepareModel = prepareModel; } public void addConfiguredPrepareEnvironment(JythonAntTask prepareEnvironment) { this.prepareEnvironment = prepareEnvironment; } /** * Process an XML file using FreeMarker */ private void process(File baseDir, String xmlFile, File destDir) throws BuildException { File outFile=null; File inFile=null; try { // the current input file relative to the baseDir inFile = new File(baseDir,xmlFile); // the output file relative to basedir outFile = new File(destDir, xmlFile.substring(0, xmlFile.lastIndexOf('.')) + extension); // only process files that have changed if (!incremental || (inFile.lastModified() > outFile.lastModified() || templateFileLastModified > outFile.lastModified() || projectFileLastModified > outFile.lastModified())) { ensureDirectoryFor(outFile); //-- command line status log("Input: " + xmlFile, Project.MSG_INFO ); if (projectTemplate == null && projectFile != null) { Document doc = builder.parse(projectFile); projectTemplate = new NodeListModel(builder.parse(projectFile)); projectNode = NodeModel.wrap(doc); } // Build the file DOM Document docNode = builder.parse(inFile); TemplateModel document = new NodeListModel(docNode); TemplateNodeModel docNodeModel = NodeModel.wrap(docNode); HashMap root = new HashMap(); root.put("document", document); insertDefaults(root); // Process the template and write out // the result as the outFile. Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), encoding)); try { if (parsedTemplate == null) { throw new BuildException("No template file specified in build script or in XML file"); } if (prepareModel != null) { Map vars = new HashMap(); vars.put("model", root); vars.put("doc", docNode); if (projectNode != null) { vars.put("project", ((NodeModel) projectNode).getNode()); } prepareModel.execute(vars); } freemarker.core.Environment env = parsedTemplate.createProcessingEnvironment(root, writer); env.setCurrentVisitorNode(docNodeModel); if (prepareEnvironment != null) { Map vars = new HashMap(); vars.put("env", env); vars.put("doc", docNode); if (projectNode != null) { vars.put("project", ((NodeModel) projectNode).getNode()); } prepareEnvironment.execute(vars); } env.process(); writer.flush(); } finally { writer.close(); } log("Output: " + outFile, Project.MSG_INFO ); } } catch (SAXParseException spe) { Throwable rootCause = spe; if (spe.getException() != null) rootCause = spe.getException(); log("XML parsing error in " + inFile.getAbsolutePath(), Project.MSG_ERR); log("Line number " + spe.getLineNumber()); log("Column number " + spe.getColumnNumber()); throw new BuildException(rootCause, getLocation()); } catch (Throwable e) { if (outFile != null ) { if(!outFile.delete() && outFile.exists()) { log("Failed to delete " + outFile, Project.MSG_WARN); } } e.printStackTrace(); throw new BuildException(e, getLocation()); } } private void generateModels() { StringTokenizer modelTokenizer = new StringTokenizer(models, ",; "); while(modelTokenizer.hasMoreTokens()) { String modelSpec = modelTokenizer.nextToken(); String name = null; String clazz = null; int sep = modelSpec.indexOf('='); if(sep == -1) { // No explicit name - use unqualified class name clazz = modelSpec; int dot = clazz.lastIndexOf('.'); if(dot == -1) { // clazz in the default package name = clazz; } else { name = clazz.substring(dot + 1); } } else { name = modelSpec.substring(0, sep); clazz = modelSpec.substring(sep + 1); } try { modelsMap.put(name, ClassUtil.forName(clazz).newInstance()); } catch(Exception e) { throw new BuildException(e); } } } /** * create directories as needed */ private void ensureDirectoryFor( File targetFile ) throws BuildException { File directory = new File( targetFile.getParent() ); if (!directory.exists()) { if (!directory.mkdirs()) { throw new BuildException("Unable to create directory: " + directory.getAbsolutePath(), getLocation()); } } } private static TemplateModel wrapMap(Map table) { SimpleHash model = new SimpleHash(); for (Iterator it = table.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry)it.next(); model.put(String.valueOf(entry.getKey()), new SimpleScalar(String.valueOf(entry.getValue()))); } return model; } protected void insertDefaults(Map root) { root.put("properties", propertiesTemplate); root.put("userProperties", userPropertiesTemplate); if (projectTemplate != null) { root.put("project", projectTemplate); root.put("project_node", projectNode); } if(modelsMap.size() > 0) { for (Iterator it = modelsMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); root.put(entry.getKey(), entry.getValue()); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/ant/JythonAntTask.java0000644000175000017500000001163711723544467025553 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.ant; import java.io.*; import java.util.Map; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.ProjectHelper; import org.apache.tools.ant.Task; import freemarker.template.utility.ClassUtil; /** * Used internally, public for technical reasons only. * *

This is an Ant sub-task of the {@link FreemarkerXmlTask} task. * *

Warning! It must not be statically linked with Jython classes, * so users can use the XML ant task even if Jython is not installed. */ public class JythonAntTask extends Task { private File scriptFile; private String script = ""; private UnlinkedJythonOperations jythonOps; public void setFile(File scriptFile) throws BuildException { ensureJythonOpsExists(); this.scriptFile = scriptFile; } public void addText(String text) { script += text; } public void execute(Map vars) throws BuildException { if (scriptFile != null) { ensureJythonOpsExists(); jythonOps.execute(scriptFile, vars); } if (script.trim().length() >0) { ensureJythonOpsExists(); String finalScript = ProjectHelper.replaceProperties( project, script, project.getProperties()); jythonOps.execute(finalScript, vars); } } private void ensureJythonOpsExists() { if (jythonOps == null) { Class clazz; try { clazz = ClassUtil.forName( "freemarker.ext.ant.UnlinkedJythonOperationsImpl"); } catch (ClassNotFoundException e) { throw new RuntimeException( "A ClassNotFoundException has been thrown when trying " + "to get the " + "freemarker.ext.ant.UnlinkedJythonOperationsImpl class. " + "The error message was: " + e.getMessage()); } try { jythonOps = (UnlinkedJythonOperations) clazz.newInstance(); } catch (Exception e) { throw new RuntimeException( "An exception has been thrown when trying " + "to create a freemarker.ext.ant.JythonAntTask " + "object. The exception was: " + e); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/ant/package.html0000644000175000017500000000026411723544470024414 0ustar ebourgebourg

An ant task that can be used to invoke the FreeMarker engine to generate documentation. libfreemarker-java-2.3.19.orig/src/freemarker/ext/jdom/0000755000175000017500000000000012164627123022275 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/jdom/NodeListModel.java0000644000175000017500000015762611723544471025667 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jdom; import java.io.FileReader; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import org.jaxen.Context; import org.jaxen.JaxenException; import org.jaxen.NamespaceContext; import org.jaxen.jdom.JDOMXPath; import org.jdom.Attribute; import org.jdom.CDATA; import org.jdom.Comment; import org.jdom.DocType; import org.jdom.Document; import org.jdom.Element; import org.jdom.EntityRef; import org.jdom.Namespace; import org.jdom.ProcessingInstruction; import org.jdom.Text; import org.jdom.output.XMLOutputter; import freemarker.template.SimpleHash; import freemarker.template.SimpleScalar; import freemarker.template.Template; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.Collections12; /** * Provides a template for wrapping JDOM objects. It is capable of storing not only * a single JDOM node, but a list of JDOM nodes at once (hence the name). * Each node is an instance of any of the core JDOM node classes (except namespaces, * which are not supported at the moment), or String for representing text. * See individual method documentation for exact details on how the class works. In * short: *

    *
  • {@link #getAsString()} will render all contained nodes as XML fragment, *
  • {@link #exec(List)} provides full XPath functionality implemented on top of * the Jaxen library,
  • *
  • {@link #get(String)} provides node traversal, copying and filtering - somewhat * less expressive than XPath, however it does not require the external library and * it evaluates somewhat faster
  • *
  • being a {@link TemplateCollectionModel} allows to iterate the contained node list, and
  • *
  • being a {@link TemplateSequenceModel} allows to access the contained nodes by index and query the node count.
  • *
* *

Note: There is a JDOM independent re-implementation of this class: * {@link freemarker.ext.xml.NodeListModel freemarker.ext.xml.NodeListModel} * * @deprecated Use {@link freemarker.ext.dom.NodeModel} instead. * @author Attila Szegedi * @version $Id: NodeListModel.java,v 1.52.2.2 2006/11/14 10:39:58 szegedia Exp $ */ public class NodeListModel implements TemplateHashModel, TemplateMethodModel, TemplateCollectionModel, TemplateSequenceModel, TemplateScalarModel { private static final AttributeXMLOutputter OUTPUT = new AttributeXMLOutputter(); // A convenience singleton for representing a node list without nodes. private static final NodeListModel EMPTY = new NodeListModel(null, false); // Cache of already parsed XPath expressions private static final Map XPATH_CACHE = new WeakHashMap(); private static final NamedNodeOperator NAMED_CHILDREN_OP = new NamedChildrenOp(); private static final NamedNodeOperator NAMED_ATTRIBUTE_OP = new NamedAttributeOp(); private static final NodeOperator ALL_ATTRIBUTES_OP = new AllAttributesOp(); private static final NodeOperator ALL_CHILDREN_OP = new AllChildrenOp(); private static final Map OPERATIONS = createOperations(); private static final Map SPECIAL_OPERATIONS = createSpecialOperations(); private static final int SPECIAL_OPERATION_COPY = 0; private static final int SPECIAL_OPERATION_UNIQUE = 1; private static final int SPECIAL_OPERATION_FILTER_NAME = 2; private static final int SPECIAL_OPERATION_FILTER_TYPE = 3; private static final int SPECIAL_OPERATION_QUERY_TYPE = 4; private static final int SPECIAL_OPERATION_REGISTER_NAMESPACE = 5; private static final int SPECIAL_OPERATION_PLAINTEXT = 6; // The contained nodes private final List nodes; private final Map namespaces; /** * Creates a node list that holds a single {@link Document} node. */ public NodeListModel(Document document) { nodes = document == null ? Collections.EMPTY_LIST : Collections12.singletonList(document); namespaces = new HashMap(); } /** * Creates a node list that holds a single {@link Element} node. */ public NodeListModel(Element element) { nodes = element == null ? Collections.EMPTY_LIST : Collections12.singletonList(element); namespaces = new HashMap(); } private NodeListModel(Object object, Map namespaces) { nodes = object == null ? Collections.EMPTY_LIST : Collections12.singletonList(object); this.namespaces = namespaces; } /** * Creates a node list that holds a list of nodes. * @param nodes the list of nodes this template should hold. The created template * will copy the passed nodes list, so changes to the passed list will not affect * the model. */ public NodeListModel(List nodes) { this(nodes, true); } /** * Creates a node list that holds a list of nodes. * @param nodes the list of nodes this template should hold. * @param copy if true, the created template will copy the passed nodes list, * so changes to the passed list will not affect the model. If false, the model * will reference the passed list and will sense changes in it, although no * operations on the list will be synchronized. */ public NodeListModel(List nodes, boolean copy) { this.nodes = copy && nodes != null ? new ArrayList(nodes) : (nodes == null ? Collections.EMPTY_LIST : nodes); namespaces = new HashMap(); } private NodeListModel(List nodes, Map namespaces) { this.nodes = nodes == null ? Collections.EMPTY_LIST : nodes; this.namespaces = namespaces; } private static final NodeListModel createNodeListModel(List list, Map namespaces) { if (list == null || list.isEmpty()) { if (namespaces.isEmpty()) { return EMPTY; } else { return new NodeListModel(Collections.EMPTY_LIST, namespaces); } } if (list.size() == 1) return new NodeListModel(list.get(0), namespaces); return new NodeListModel(list, namespaces); } /** * Returns true if this model contains no nodes. */ public boolean isEmpty() { return nodes.isEmpty(); } /** * This method returns the string resulting from concatenation * of string representations of its nodes. Each node is rendered using its XML * serialization format, while text (String) is rendered as itself. This greatly * simplifies creating XML-transformation templates, as to output a node contained * in variable x as XML fragment, you simply write ${x} in the template. */ public String getAsString() throws TemplateModelException { if (isEmpty()) return ""; java.io.StringWriter sw = new java.io.StringWriter(nodes.size() * 128); try { for (Iterator i = nodes.iterator(); i.hasNext();) { Object node = i.next(); if (node instanceof Element) OUTPUT.output((Element)node, sw); else if (node instanceof Attribute) OUTPUT.output((Attribute)node, sw); else if (node instanceof String) sw.write(OUTPUT.escapeElementEntities(node.toString())); else if (node instanceof Text) OUTPUT.output((Text)node, sw); else if (node instanceof Document) OUTPUT.output((Document)node, sw); else if (node instanceof ProcessingInstruction) OUTPUT.output((ProcessingInstruction)node, sw); else if (node instanceof Comment) OUTPUT.output((Comment)node, sw); else if (node instanceof CDATA) OUTPUT.output((CDATA)node, sw); else if (node instanceof DocType) OUTPUT.output((DocType)node, sw); else if (node instanceof EntityRef) OUTPUT.output((EntityRef)node, sw); else throw new TemplateModelException(node.getClass().getName() + " is not a core JDOM class"); } } catch (IOException e) { throw new TemplateModelException(e.getMessage()); } return sw.toString(); } /** * 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 _ftype * key to explicitly filter out undesired node types prior to applying the * restricted-applicability key. Also "current nodes" means nodes contained in this * set. *

    *
  • * or _children: all direct element children of current nodes (non-recursive). Applicable * to element and document nodes.
  • *
  • @* or _attributes: all attributes of current nodes. Applicable to elements only.
  • *
  • _content the complete content of current nodes (non-recursive). * Applicable to elements and documents.
  • *
  • _text: 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.
  • *
  • _plaintext: same as _text, but does not escape any characters, * and instead of returning a NodeList returns a SimpleScalar.
  • *
  • _name: 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)
  • *
  • _qname: the qualified names of current nodes in [namespacePrefix:]localName * form, one string per node (non-recursive). Applicable to elements and attributes
  • *
  • _cname: the canonical names of current nodes (namespace URI + local name), * one string per node (non-recursive). Applicable to elements and attributes
  • *
  • _nsprefix: namespace prefixes of current nodes, * one string per node (non-recursive). Applicable to elements and attributes
  • *
  • _nsuri: namespace URIs of current nodes, * one string per node (non-recursive). Applicable to elements and attributes
  • *
  • _parent: parent elements of current nodes. Applicable to element, attribute, comment, * entity, processing instruction.
  • *
  • _ancestor: all ancestors up to root element (recursive) of current nodes. Applicable * to same node types as _parent.
  • *
  • _ancestorOrSelf: all ancestors of current nodes plus current nodes. Applicable * to same node types as _parent.
  • *
  • _descendant: all recursive descendant element children of current nodes. Applicable to * document and element nodes. *
  • _descendantOrSelf: all recursive descendant element children of current nodes * plus current nodes. Applicable to document and element nodes. *
  • _document: all documents the current nodes belong to. * Applicable to all nodes except text. *
  • _doctype: doctypes of the current nodes. * Applicable to document nodes only. *
  • _fname: 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.
  • *
  • _ftype: 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.
  • *
  • _type: 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.
  • *
  • _unique: 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 _parent, * _ancestor, _ancestorOrSelf, and _document. * I.e. foo._children._parent 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 * foo._children._parent._unique to eliminate duplicates. Applicable * to all node types.
  • *
  • _copy: 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.
  • *
  • _registerNamespace(prefix, uri): 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 nodelist["prefix:localname"] or * nodelist["@prefix:localname"] 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. *
  • *
  • @attributeName: named attributes of current nodes. Applicable to * elements, doctypes and processing instructions. On doctypes it supports * attributes publicId, systemId and elementName. On processing * instructions, it supports attributes target and data, as * well as any other attribute name specified in data as name="value" pair. * The attribute nodes for doctype and processing instruction are synthetic, and * as such have no parent. Note, however that @* does NOT operate on * doctypes or processing instructions.
  • *
  • any other key: element children of current nodes with name matching the key. * This allows for convenience child traversal in book.chapter.title style syntax. * Note that nodeset.childname is technically equivalent to * nodeset._children._fname("childname"), but is both shorter to write * and evaluates faster. Applicable to document and element nodes.
  • *
* 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); } private TemplateModel getType() { if (nodes.size() == 0) return new SimpleScalar(""); Object firstNode = nodes.get(0); char code; if (firstNode instanceof Element) code = 'e'; else if (firstNode instanceof Text || firstNode instanceof String) code = 'x'; else if (firstNode instanceof Attribute) code = 'a'; else if (firstNode instanceof EntityRef) code = 'n'; else if (firstNode instanceof Document) code = 'd'; else if (firstNode instanceof DocType) code = 't'; else if (firstNode instanceof Comment) code = 'c'; else if (firstNode instanceof ProcessingInstruction) code = 'p'; else code = '?'; return new SimpleScalar(new String(new char[] { code})); } private SimpleScalar getPlainText() throws TemplateModelException { List list = evaluateElementOperation((TextOp)OPERATIONS.get("_text"), nodes); StringBuffer buf = new StringBuffer(); for (Iterator it = list.iterator(); it.hasNext();) { buf.append(it.next()); } return new SimpleScalar(buf.toString()); } public TemplateModelIterator iterator() { return new TemplateModelIterator() { private final Iterator it = nodes.iterator(); public TemplateModel next() { return it.hasNext() ? new NodeListModel(it.next(), namespaces) : null; } public boolean hasNext() { return it.hasNext(); } }; } /** * Retrieves the i-th element of the node list. */ public TemplateModel get(int i) throws TemplateModelException { try { return new NodeListModel(nodes.get(i), namespaces); } catch (IndexOutOfBoundsException e) { throw new TemplateModelException("Index out of bounds: " + e.getMessage()); } } public int size() { return nodes.size(); } /** * 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 * Jaxen 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 nodelist._registerNamespace(prefix, uri) 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); } } /** * Registers an XML namespace with this node list. Once registered, you can * refer to the registered namespace using its prefix in the * {@link #get(String)} method from this node list and all other * node lists that are derived from this node list. Use the * nodelist["prefix:localname"] or the * nodelist["@prefix:localname"] syntax 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 during template evaluation using the * nodelist._registerNamespace(prefix, uri) syntax in the template. * This mechanism is completely independent from the namespace declarations * in the XML document itself; its purpose is to give you an easy way * to refer to namespace-scoped elements in {@link #get(String)} and * in XPath expressions passed to {@link #exec(List)}. Note also that * the namespace prefix registry is shared among all node lists that * are created from a single node list - modifying the registry in one * affects all others as well. If you want to obtain a namespace * "detached" copy of the node list, use the _copy key on * it (or call nodeList.get("_copy") directly from your * Java code. The returned node list has all the namespaces that the * original node list has, but they can be manipulated independently * thereon. */ public void registerNamespace(String prefix, String uri) { synchronized(namespaces) { namespaces.put(prefix, Namespace.getNamespace(prefix, uri)); } } private interface NodeOperator { List operate(Object node) throws TemplateModelException; } private interface NamedNodeOperator { List operate(Object node, String localName, Namespace namespace) throws TemplateModelException; } private static final class AllChildrenOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return((Element)node).getChildren(); else if (node instanceof Document) { Element root = ((Document)node).getRootElement(); return root == null ? Collections.EMPTY_LIST : Collections12.singletonList(root); } // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; /* else throw new TemplateModelException("_allChildren can not be applied on " + node.getClass()); */ } } private static final class NamedChildrenOp implements NamedNodeOperator { public List operate(Object node, String localName, Namespace namespace) { if (node instanceof Element) { return((Element)node).getChildren(localName, namespace); } else if (node instanceof Document) { Element root = ((Document)node).getRootElement(); if (root != null && root.getName().equals(localName) && root.getNamespaceURI().equals(namespace.getURI())) { return Collections12.singletonList(root); } else return Collections.EMPTY_LIST; } // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; /* else throw new TemplateModelException("_namedChildren can not be applied on " + node.getClass()); */ } } private static final class AllAttributesOp implements NodeOperator { public List operate(Object node) { // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) if (!(node instanceof Element)) { return null; } return ((Element)node).getAttributes(); /* else throw new TemplateModelException("_allAttributes can not be applied on " + node.getClass()); */ } } private static final class NamedAttributeOp implements NamedNodeOperator { public List operate(Object node, String localName, Namespace namespace) { Attribute attr = null; if (node instanceof Element) { Element element = (Element)node; attr = element.getAttribute(localName, namespace); } else if (node instanceof ProcessingInstruction) { ProcessingInstruction pi = (ProcessingInstruction)node; if ("target".equals(localName)) attr = new Attribute("target", pi.getTarget()); else if ("data".equals(localName)) attr = new Attribute("data", pi.getData()); else attr = new Attribute(localName, pi.getValue(localName)); } else if (node instanceof DocType) { DocType doctype = (DocType)node; if ("publicId".equals(localName)) attr = new Attribute("publicId", doctype.getPublicID()); else if ("systemId".equals(localName)) attr = new Attribute("systemId", doctype.getSystemID()); else if ("elementName".equals(localName)) attr = new Attribute("elementName", doctype.getElementName()); } // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) else { return null; } /* else throw new TemplateModelException("_allAttributes can not be applied on " + node.getClass()); */ return attr == null ? Collections.EMPTY_LIST : Collections12.singletonList(attr); } } private static final class NameOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return Collections12.singletonList(((Element)node).getName()); else if (node instanceof Attribute) return Collections12.singletonList(((Attribute)node).getName()); else if (node instanceof EntityRef) return Collections12.singletonList(((EntityRef)node).getName()); else if (node instanceof ProcessingInstruction) return Collections12.singletonList(((ProcessingInstruction)node).getTarget()); else if (node instanceof DocType) return Collections12.singletonList(((DocType)node).getPublicID()); else return null; // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) // throw new TemplateModelException("_name can not be applied on " + node.getClass()); } } private static final class QNameOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return Collections12.singletonList(((Element)node).getQualifiedName()); else if (node instanceof Attribute) return Collections12.singletonList(((Attribute)node).getQualifiedName()); // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_qname can not be applied on " + node.getClass()); } } private static final class NamespaceUriOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return Collections12.singletonList(((Element)node).getNamespace().getURI()); else if (node instanceof Attribute) return Collections12.singletonList(((Attribute)node).getNamespace().getURI()); // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_nsuri can not be applied on " + node.getClass()); } } private static final class NamespacePrefixOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return Collections12.singletonList(((Element)node).getNamespace().getPrefix()); else if (node instanceof Attribute) return Collections12.singletonList(((Attribute)node).getNamespace().getPrefix()); // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_nsprefix can not be applied on " + node.getClass()); } } private static final class CanonicalNameOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) { Element element = (Element)node; return Collections12.singletonList(element.getNamespace().getURI() + element.getName()); } else if (node instanceof Attribute) { Attribute attribute = (Attribute)node; return Collections12.singletonList(attribute.getNamespace().getURI() + attribute.getName()); } // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_cname can not be applied on " + node.getClass()); } } private static final Element getParent(Object node) { if (node instanceof Element) return((Element)node).getParent(); else if (node instanceof Attribute) return((Attribute)node).getParent(); else if (node instanceof Text) return((Text)node).getParent(); else if (node instanceof ProcessingInstruction) return((ProcessingInstruction)node).getParent(); else if (node instanceof Comment) return((Comment)node).getParent(); else if (node instanceof EntityRef) return((EntityRef)node).getParent(); else // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_parent can not be applied on " + node.getClass()); } private static final class ParentOp implements NodeOperator { public List operate(Object node) { Element parent = getParent(node); return parent == null ? Collections.EMPTY_LIST : Collections12.singletonList(parent); } } private static final class AncestorOp implements NodeOperator { public List operate(Object node) { Element parent = getParent(node); if (parent == null) return Collections.EMPTY_LIST; LinkedList list = new LinkedList(); do { list.addFirst(parent); parent = parent.getParent(); } while (parent != null); return list; } } private static final class AncestorOrSelfOp implements NodeOperator { public List operate(Object node) { Element parent = getParent(node); if (parent == null) return Collections12.singletonList(node); LinkedList list = new LinkedList(); list.addFirst(node); do { list.addFirst(parent); parent = parent.getParent(); } while (parent != null); return list; } } private static class DescendantOp implements NodeOperator { public List operate(Object node) { LinkedList list = new LinkedList(); if (node instanceof Element) { addChildren((Element)node, list); } else if (node instanceof Document) { Element root = ((Document)node).getRootElement(); list.add(root); addChildren(root, list); } else // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_descendant can not be applied on " + node.getClass()); return list; } private void addChildren(Element element, List list) { List children = element.getChildren(); Iterator it = children.iterator(); while (it.hasNext()) { Element child = (Element)it.next(); list.add(child); addChildren(child, list); } } } private static final class DescendantOrSelfOp extends DescendantOp { public List operate(Object node) { LinkedList list = (LinkedList)super.operate(node); list.addFirst(node); return list; } } private static final class DocumentOp implements NodeOperator { public List operate(Object node) { Document doc = null; if (node instanceof Element) doc = ((Element)node).getDocument(); else if (node instanceof Attribute) { Element parent = ((Attribute)node).getParent(); doc = parent == null ? null : parent.getDocument(); } else if (node instanceof Text) { Element parent = ((Text)node).getParent(); doc = parent == null ? null : parent.getDocument(); } else if (node instanceof Document) doc = (Document)node; else if (node instanceof ProcessingInstruction) doc = ((ProcessingInstruction)node).getDocument(); else if (node instanceof EntityRef) doc = ((EntityRef)node).getDocument(); else if (node instanceof Comment) doc = ((Comment)node).getDocument(); else // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_document can not be applied on " + node.getClass()); return doc == null ? Collections.EMPTY_LIST : Collections12.singletonList(doc); } } private static final class DocTypeOp implements NodeOperator { public List operate(Object node) { if (node instanceof Document) { DocType doctype = ((Document)node).getDocType(); return doctype == null ? Collections.EMPTY_LIST : Collections12.singletonList(doctype); } else // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_doctype can not be applied on " + node.getClass()); } } private static final class ContentOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return((Element)node).getContent(); else if (node instanceof Document) return((Document)node).getContent(); // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_content can not be applied on " + node.getClass()); } } private static final class TextOp implements NodeOperator { public List operate(Object node) { if (node instanceof Element) return Collections12.singletonList(((Element)node).getTextTrim()); if (node instanceof Attribute) return Collections12.singletonList(((Attribute)node).getValue()); if (node instanceof CDATA) return Collections12.singletonList(((CDATA)node).getText()); if (node instanceof Comment) return Collections12.singletonList(((Comment)node).getText()); if (node instanceof ProcessingInstruction) return Collections12.singletonList(((ProcessingInstruction)node).getData()); // With 2.1 semantics it makes more sense to just return a null and let the core // throw an InvalidReferenceException and the template writer can use ?exists etcetera. (JR) return null; // throw new TemplateModelException("_text can not be applied on " + node.getClass()); } } private static final List evaluateElementOperation(NodeOperator op, List nodes) throws TemplateModelException { int s = nodes.size(); List[] lists = new List[s]; int l = 0; { int i = 0; Iterator it = nodes.iterator(); while (it.hasNext()) { List list = op.operate(it.next()); if (list != null) { lists[i++] = list; l += list.size(); } } } List retval = new ArrayList(l); for (int i = 0; i < s; ++i) { if (lists[i] != null) { retval.addAll(lists[i]); } } return retval; } private static final List evaluateNamedElementOperation(NamedNodeOperator op, String localName, Namespace namespace, List nodes) throws TemplateModelException { int s = nodes.size(); List[] lists = new List[s]; int l = 0; { int i = 0; Iterator it = nodes.iterator(); while (it.hasNext()) { List list = op.operate(it.next(), localName, namespace); lists[i++] = list; l += list.size(); } } List retval = new ArrayList(l); for (int i = 0; i < s; ++i) retval.addAll(lists[i]); return retval; } private static final List removeDuplicates(List list) { int s = list.size(); ArrayList ulist = new ArrayList(s); Set set = new HashSet(s * 4 / 3, .75f); Iterator it = list.iterator(); while (it.hasNext()) { Object o = it.next(); if (set.add(o)) ulist.add(o); } ulist.trimToSize(); return ulist; } private static final Map createOperations() { Map map = new HashMap(); map.put("_ancestor", new AncestorOp()); map.put("_ancestorOrSelf", new AncestorOrSelfOp()); map.put("_attributes", ALL_ATTRIBUTES_OP); map.put("_children", ALL_CHILDREN_OP); map.put("_cname", new CanonicalNameOp()); map.put("_content", new ContentOp()); map.put("_descendant", new DescendantOp()); map.put("_descendantOrSelf", new DescendantOrSelfOp()); map.put("_document", new DocumentOp()); map.put("_doctype", new DocTypeOp()); map.put("_name", new NameOp()); map.put("_nsprefix", new NamespacePrefixOp()); map.put("_nsuri", new NamespaceUriOp()); map.put("_parent", new ParentOp()); map.put("_qname", new QNameOp()); map.put("_text", new TextOp()); return map; } private static final Map createSpecialOperations() { Map map = new HashMap(); Integer copy = new Integer(SPECIAL_OPERATION_COPY); Integer unique = new Integer(SPECIAL_OPERATION_UNIQUE); Integer fname = new Integer(SPECIAL_OPERATION_FILTER_NAME); Integer ftype = new Integer(SPECIAL_OPERATION_FILTER_TYPE); Integer type = new Integer(SPECIAL_OPERATION_QUERY_TYPE); Integer regns = new Integer(SPECIAL_OPERATION_REGISTER_NAMESPACE); Integer plaintext = new Integer(SPECIAL_OPERATION_PLAINTEXT); map.put("_copy", copy); map.put("_unique", unique); map.put("_fname", fname); map.put("_ftype", ftype); map.put("_type", type); map.put("_registerNamespace", regns); map.put("_plaintext", plaintext); // These are in for backward compatibility map.put("x_copy", copy); map.put("x_unique", unique); map.put("x_fname", fname); map.put("x_ftype", ftype); map.put("x_type", type); return map; } private final class RegisterNamespace implements TemplateMethodModel { public boolean isEmpty() { return false; } public Object exec(List arguments) throws TemplateModelException { if (arguments.size() != 2) throw new TemplateModelException("_registerNamespace(prefix, uri) requires two arguments"); registerNamespace((String)arguments.get(0), (String)arguments.get(1)); return TemplateScalarModel.EMPTY_STRING; } } private final class NameFilter implements TemplateMethodModel { public boolean isEmpty() { return false; } public Object exec(List arguments) { Set names = new HashSet(arguments); List list = new LinkedList(nodes); Iterator it = list.iterator(); while (it.hasNext()) { Object node = it.next(); String name = null; if (node instanceof Element) name = ((Element)node).getName(); else if (node instanceof Attribute) name = ((Attribute)node).getName(); else if (node instanceof ProcessingInstruction) name = ((ProcessingInstruction)node).getTarget(); else if (node instanceof EntityRef) name = ((EntityRef)node).getName(); else if (node instanceof DocType) name = ((DocType)node).getPublicID(); if (name == null || !names.contains(name)) it.remove(); } return createNodeListModel(list, namespaces); } } private final class TypeFilter implements TemplateMethodModel { public boolean isEmpty() { return false; } public Object exec(List arguments) throws TemplateModelException { if (arguments == null || arguments.size() == 0) throw new TemplateModelException("_type expects exactly one argument"); String arg = (String)arguments.get(0); boolean invert = arg.indexOf('!') != -1; // NOTE: true in each of these variables means 'remove', not 'keep' // This is so we don't invert their values in the loop. So, // a is true <--> (a is not present in the string) xor invert. boolean a = invert != (arg.indexOf('a') == -1); boolean c = invert != (arg.indexOf('c') == -1); boolean d = invert != (arg.indexOf('d') == -1); boolean e = invert != (arg.indexOf('e') == -1); boolean n = invert != (arg.indexOf('n') == -1); boolean p = invert != (arg.indexOf('p') == -1); boolean t = invert != (arg.indexOf('t') == -1); boolean x = invert != (arg.indexOf('x') == -1); LinkedList list = new LinkedList(nodes); Iterator it = list.iterator(); while (it.hasNext()) { Object node = it.next(); if ((node instanceof Element && e) || (node instanceof Attribute && a) || (node instanceof String && x) || (node instanceof Text && x) || (node instanceof ProcessingInstruction && p) || (node instanceof Comment && c) || (node instanceof EntityRef && n) || (node instanceof Document && d) || (node instanceof DocType && t)) it.remove(); } return createNodeListModel(list, namespaces); } } /** * Loads a template from a file passed as the first argument, loads an XML * document from the standard input, passes it to the template as variable * document and writes the result of template processing to * standard output. */ public static void main(String[] args) throws Exception { org.jdom.input.SAXBuilder builder = new org.jdom.input.SAXBuilder(); Document document = builder.build(System.in); SimpleHash model = new SimpleHash(); model.put("document", new NodeListModel(document)); FileReader fr = new FileReader(args[0]); Template template = new Template(args[0], fr); Writer w = new java.io.OutputStreamWriter(System.out); template.process(model, w); w.flush(); w.close(); } private static final class AttributeXMLOutputter extends XMLOutputter { public void output(Attribute attribute, Writer out) throws IOException { out.write(" "); out.write(attribute.getQualifiedName()); out.write("="); out.write("\""); out.write(escapeAttributeEntities(attribute.getValue())); out.write("\""); } } private static final class JDOMXPathEx extends JDOMXPath { JDOMXPathEx(String path) throws JaxenException { super(path); } public List selectNodes(Object object, Map namespaces) throws JaxenException { Context context = getContext(object); context.getContextSupport().setNamespaceContext(new NamespaceContextImpl(namespaces)); return selectNodesForContext(context); } private static final class NamespaceContextImpl implements NamespaceContext { private final Map namespaces; NamespaceContextImpl(Map namespaces) { this.namespaces = namespaces; } public String translateNamespacePrefixToUri(String prefix) { // Empty prefix always maps to empty URL in XPath if(prefix.length() == 0) { return prefix; } synchronized(namespaces) { Namespace ns = (Namespace)namespaces.get(prefix); return ns == null ? null : ns.getURI(); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jdom/package.html0000644000175000017500000000050411723544471024561 0ustar ebourgebourg

Provides adapter for JDOM including support for writing XML fragments, listing nodes, traversal, copying, and filtering, and a full XPath support.

libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/0000755000175000017500000000000012164627123023030 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/FreemarkerServlet.java0000644000175000017500000011144011723544470027327 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.servlet; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Enumeration; import java.util.GregorianCalendar; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import freemarker.cache.ClassTemplateLoader; import freemarker.cache.FileTemplateLoader; import freemarker.cache.TemplateLoader; import freemarker.cache.WebappTemplateLoader; import freemarker.core.Configurable; import freemarker.ext.jsp.TaglibFactory; import freemarker.log.Logger; import freemarker.template.Configuration; import freemarker.template.ObjectWrapper; import freemarker.template.Template; import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.StringUtil; import java.util.Locale; /** *

This is a general-purpose FreeMarker view servlet.

* *

The main features are: * *

    * *
  • It makes all request, request parameters, session, and servlet * context attributes available to templates through Request, * RequestParameters, Session, and Application * variables. * *
  • The scope variables are also available via automatic scope discovery. That is, * writing Application.attrName, Session.attrName, * Request.attrName is not mandatory; it's enough to write attrName, * and if no such variable was created in the template, it will search the * variable in Request, and then in Session, * and finally in Application. * *
  • It creates a variable with name JspTaglibs, that can be used * to load JSP taglibs. For example:
    * <#assign tiles=JspTaglibs["/WEB-INF/struts-tiles.tld"]> * *
  • A custom directive named include_page allows you to * include the output of another servlet resource from your servlet container, * just as if you used ServletRequest.getRequestDispatcher(path).include():
    * <@include_page path="/myWebapp/somePage.jsp"/>. You can also * pass parameters to the newly included page by passing a hash named 'params': * <@include_page path="/myWebapp/somePage.jsp" params={lang: "en", q="5"}/>. * By default, the request parameters of the original request (the one being * processed by FreemarkerServlet) are also inherited by the include. You can * explicitly control this inheritance using the 'inherit_params' parameter: * <@include_page path="/myWebapp/somePage.jsp" params={lang: "en", q="5"} inherit_params=false/>. *
* *

The servlet will rethrow the errors occurring during template processing, * wrapped into ServletException, except if the class name of the * class set by the template_exception_handler contains the * substring "Debug". If it contains "Debug", then it * is assumed that the template exception handler prints the error message to the * page, thus FreemarkerServlet will suppress the exception, and * logs the problem with the servlet logger * (javax.servlet.GenericServlet.log(...)). * *

Supported init-params are:

* *
    * *
  • TemplatePath specifies the location of the templates. * By default, this is interpreted as web application directory relative URI.
    * Alternatively, you can prepend it with file:// to indicate a literal * path in the file system (i.e. file:///var/www/project/templates/). * Note that three slashes were used to specify an absolute path.
    * Also, you can prepend it with class://path/to/template/package to * indicate that you want to load templates from the specified package * accessible through the classloader of the servlet.
    * Default value is class:// (that is, the root of the class hierarchy). * Note that this default is different than the default in FreeMarker 1.x, when * it defaulted /, that is to loading from the webapp root directory.
  • * *
  • NoCache if set to true, generates headers in the response * that advise the HTTP client not to cache the returned page. * The default is false.
  • * *
  • ContentType if specified, response uses the specified * Content-type HTTP header. The value may include the charset (e.g. * "text/html; charset=ISO-8859-1"). If not specified, "text/html" * is used. If the charset is not specified in this init-param, then the charset * (encoding) of the actual template file will be used (in the response HTTP header * and for encoding the output stream). Note that this setting can be overridden * on a per-template basis by specifying a custom attribute named * content_type in the attributes parameter of the * <#ftl> directive. *
  • * *
  • The following init-params are supported only for backward compatibility, and * their usage is discouraged: TemplateUpdateInterval, DefaultEncoding, * ObjectWrapper, TemplateExceptionHandler. Use setting init-params such as * object_wrapper instead. * *
  • Any other init-param will be interpreted as Configuration * level setting. See {@link Configuration#setSetting}
  • * *
* * @author Attila Szegedi * @version $Id: FreemarkerServlet.java,v 1.82.2.5 2006/06/21 13:02:01 ddekany Exp $ */ public class FreemarkerServlet extends HttpServlet { private static final Logger logger = Logger.getLogger("freemarker.servlet"); public static final long serialVersionUID = -2440216393145762479L; private static final String INITPARAM_TEMPLATE_PATH = "TemplatePath"; private static final String INITPARAM_NOCACHE = "NoCache"; private static final String INITPARAM_CONTENT_TYPE = "ContentType"; private static final String DEFAULT_CONTENT_TYPE = "text/html"; private static final String INITPARAM_DEBUG = "Debug"; private static final String DEPR_INITPARAM_TEMPLATE_DELAY = "TemplateDelay"; private static final String DEPR_INITPARAM_ENCODING = "DefaultEncoding"; private static final String DEPR_INITPARAM_OBJECT_WRAPPER = "ObjectWrapper"; private static final String DEPR_INITPARAM_WRAPPER_SIMPLE = "simple"; private static final String DEPR_INITPARAM_WRAPPER_BEANS = "beans"; private static final String DEPR_INITPARAM_WRAPPER_JYTHON = "jython"; private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER = "TemplateExceptionHandler"; private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW = "rethrow"; private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG = "debug"; private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_HTML_DEBUG = "htmlDebug"; private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_IGNORE = "ignore"; private static final String DEPR_INITPARAM_DEBUG = "debug"; public static final String KEY_REQUEST = "Request"; public static final String KEY_INCLUDE = "include_page"; public static final String KEY_REQUEST_PRIVATE = "__FreeMarkerServlet.Request__"; public static final String KEY_REQUEST_PARAMETERS = "RequestParameters"; public static final String KEY_SESSION = "Session"; public static final String KEY_APPLICATION = "Application"; public static final String KEY_APPLICATION_PRIVATE = "__FreeMarkerServlet.Application__"; public static final String KEY_JSP_TAGLIBS = "JspTaglibs"; // Note these names start with dot, so they're essentially invisible from // a freemarker script. private static final String ATTR_REQUEST_MODEL = ".freemarker.Request"; private static final String ATTR_REQUEST_PARAMETERS_MODEL = ".freemarker.RequestParameters"; private static final String ATTR_SESSION_MODEL = ".freemarker.Session"; private static final String ATTR_APPLICATION_MODEL = ".freemarker.Application"; private static final String ATTR_JSP_TAGLIBS_MODEL = ".freemarker.JspTaglibs"; private static final String EXPIRATION_DATE; static { // Generate expiration date that is one year from now in the past GregorianCalendar expiration = new GregorianCalendar(); expiration.roll(Calendar.YEAR, -1); SimpleDateFormat httpDate = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", java.util.Locale.US); EXPIRATION_DATE = httpDate.format(expiration.getTime()); } private String templatePath; private boolean nocache; protected boolean debug; private Configuration config; private ObjectWrapper wrapper; private String contentType; private boolean noCharsetInContentType; public void init() throws ServletException { try { config = createConfiguration(); // Set defaults: config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER); contentType = DEFAULT_CONTENT_TYPE; // Process object_wrapper init-param out of order: wrapper = createObjectWrapper(); if (logger.isDebugEnabled()) { logger.debug("Using object wrapper of class " + wrapper.getClass().getName()); } config.setObjectWrapper(wrapper); // Process TemplatePath init-param out of order: templatePath = getInitParameter(INITPARAM_TEMPLATE_PATH); if (templatePath == null) templatePath = "class://"; config.setTemplateLoader(createTemplateLoader(templatePath)); // Process all other init-params: Enumeration initpnames = getServletConfig().getInitParameterNames(); while (initpnames.hasMoreElements()) { String name = (String) initpnames.nextElement(); String value = getInitParameter(name); if (name == null) { throw new ServletException( "init-param without param-name. " + "Maybe the web.xml is not well-formed?"); } if (value == null) { throw new ServletException( "init-param without param-value. " + "Maybe the web.xml is not well-formed?"); } if (name.equals(DEPR_INITPARAM_OBJECT_WRAPPER) || name.equals(Configurable.OBJECT_WRAPPER_KEY) || name.equals(INITPARAM_TEMPLATE_PATH)) { // ignore: we have already processed these } else if (name.equals(DEPR_INITPARAM_ENCODING)) { // BC if (getInitParameter(Configuration.DEFAULT_ENCODING_KEY) != null) { throw new ServletException( "Conflicting init-params: " + Configuration.DEFAULT_ENCODING_KEY + " and " + DEPR_INITPARAM_ENCODING); } config.setDefaultEncoding(value); } else if (name.equals(DEPR_INITPARAM_TEMPLATE_DELAY)) { // BC if (getInitParameter(Configuration.TEMPLATE_UPDATE_DELAY_KEY) != null) { throw new ServletException( "Conflicting init-params: " + Configuration.TEMPLATE_UPDATE_DELAY_KEY + " and " + DEPR_INITPARAM_TEMPLATE_DELAY); } try { config.setTemplateUpdateDelay(Integer.parseInt(value)); } catch (NumberFormatException e) { // Intentionally ignored } } else if (name.equals(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER)) { // BC if (getInitParameter(Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY) != null) { throw new ServletException( "Conflicting init-params: " + Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY + " and " + DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER); } if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW.equals(value)) { config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); } else if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG.equals(value)) { config.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER); } else if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_HTML_DEBUG.equals(value)) { config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER); } else if (DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_IGNORE.equals(value)) { config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); } else { throw new ServletException( "Invalid value for servlet init-param " + DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER + ": " + value); } } else if (name.equals(INITPARAM_NOCACHE)) { nocache = StringUtil.getYesNo(value); } else if (name.equals(DEPR_INITPARAM_DEBUG)) { // BC if (getInitParameter(INITPARAM_DEBUG) != null) { throw new ServletException( "Conflicting init-params: " + INITPARAM_DEBUG + " and " + DEPR_INITPARAM_DEBUG); } debug = StringUtil.getYesNo(value); } else if (name.equals(INITPARAM_DEBUG)) { debug = StringUtil.getYesNo(value); } else if (name.equals(INITPARAM_CONTENT_TYPE)) { contentType = value; } else { config.setSetting(name, value); } } // while initpnames noCharsetInContentType = true; int i = contentType.toLowerCase().indexOf("charset="); if (i != -1) { char c = ' '; i--; while (i >= 0) { c = contentType.charAt(i); if (!Character.isWhitespace(c)) break; i--; } if (i == -1 || c == ';') { noCharsetInContentType = false; } } } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException(e); } } /** * Create the template loader. The default implementation will create a * {@link ClassTemplateLoader} if the template path starts with "class://", * a {@link FileTemplateLoader} if the template path starts with "file://", * and a {@link WebappTemplateLoader} otherwise. * @param templatePath the template path to create a loader for * @return a newly created template loader * @throws IOException */ protected TemplateLoader createTemplateLoader(String templatePath) throws IOException { if (templatePath.startsWith("class://")) { // substring(7) is intentional as we "reuse" the last slash return new ClassTemplateLoader(getClass(), templatePath.substring(7)); } else { if (templatePath.startsWith("file://")) { templatePath = templatePath.substring(7); return new FileTemplateLoader(new File(templatePath)); } else { return new WebappTemplateLoader(this.getServletContext(), templatePath); } } } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { process(request, response); } public void doPost( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { process(request, response); } private void process( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Give chance to subclasses to perform preprocessing if (preprocessRequest(request, response)) { return; } String path = requestUrlToTemplatePath(request); if (debug) { log("Requested template: " + StringUtil.jQuoteNoXSS(path)); } Template template = null; try { template = config.getTemplate( path, deduceLocale(path, request, response)); } catch (FileNotFoundException e) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } Object attrContentType = template.getCustomAttribute("content_type"); if(attrContentType != null) { response.setContentType(attrContentType.toString()); } else { if (noCharsetInContentType) { response.setContentType( contentType + "; charset=" + template.getEncoding()); } else { response.setContentType(contentType); } } // Set cache policy setBrowserCachingPolicy(response); ServletContext servletContext = getServletContext(); try { TemplateModel model = createModel(wrapper, servletContext, request, response); // Give subclasses a chance to hook into preprocessing if (preTemplateProcess(request, response, template, model)) { try { // Process the template template.process(model, response.getWriter()); } finally { // Give subclasses a chance to hook into postprocessing postTemplateProcess(request, response, template, model); } } } catch (TemplateException te) { if (config.getTemplateExceptionHandler() .getClass().getName().indexOf("Debug") != -1) { this.log("Error executing FreeMarker template", te); } else { ServletException e = new ServletException( "Error executing FreeMarker template", te); // Attempt to set init cause, but don't freak out if the method // is not available (i.e. pre-1.4 JRE). This is required as the // constructor-passed throwable won't show up automatically in // stack traces. try { e.getClass().getMethod("initCause", new Class[] { Throwable.class }).invoke(e, new Object[] { te }); } catch (Exception ex) { // Can't set init cause, we're probably running on a pre-1.4 // JDK, oh well... } throw e; } } } /** * Returns the locale used for the * {@link Configuration#getTemplate(String, Locale)} call. * The base implementation simply returns the locale setting of the * configuration. Override this method to provide different behaviour, i.e. * to use the locale indicated in the request. */ protected Locale deduceLocale( String templatePath, HttpServletRequest request, HttpServletResponse response) { return config.getLocale(); } protected TemplateModel createModel(ObjectWrapper wrapper, ServletContext servletContext, final HttpServletRequest request, final HttpServletResponse response) throws TemplateModelException { try { AllHttpScopesHashModel params = new AllHttpScopesHashModel(wrapper, servletContext, request); // Create hash model wrapper for servlet context (the application) ServletContextHashModel servletContextModel = (ServletContextHashModel) servletContext.getAttribute( ATTR_APPLICATION_MODEL); if (servletContextModel == null) { servletContextModel = new ServletContextHashModel(this, wrapper); servletContext.setAttribute( ATTR_APPLICATION_MODEL, servletContextModel); TaglibFactory taglibs = new TaglibFactory(servletContext); servletContext.setAttribute( ATTR_JSP_TAGLIBS_MODEL, taglibs); initializeServletContext(request, response); } params.putUnlistedModel(KEY_APPLICATION, servletContextModel); params.putUnlistedModel(KEY_APPLICATION_PRIVATE, servletContextModel); params.putUnlistedModel(KEY_JSP_TAGLIBS, (TemplateModel)servletContext.getAttribute(ATTR_JSP_TAGLIBS_MODEL)); // Create hash model wrapper for session HttpSessionHashModel sessionModel; HttpSession session = request.getSession(false); if(session != null) { sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL); if (sessionModel == null || sessionModel.isOrphaned(session)) { sessionModel = new HttpSessionHashModel(session, wrapper); initializeSessionAndInstallModel(request, response, sessionModel, session); } } else { sessionModel = new HttpSessionHashModel(this, request, response, wrapper); } params.putUnlistedModel(KEY_SESSION, sessionModel); // Create hash model wrapper for request HttpRequestHashModel requestModel = (HttpRequestHashModel) request.getAttribute(ATTR_REQUEST_MODEL); if (requestModel == null || requestModel.getRequest() != request) { requestModel = new HttpRequestHashModel(request, response, wrapper); request.setAttribute(ATTR_REQUEST_MODEL, requestModel); request.setAttribute( ATTR_REQUEST_PARAMETERS_MODEL, createRequestParametersHashModel(request)); } params.putUnlistedModel(KEY_REQUEST, requestModel); params.putUnlistedModel(KEY_INCLUDE, new IncludePage(request, response)); params.putUnlistedModel(KEY_REQUEST_PRIVATE, requestModel); // Create hash model wrapper for request parameters HttpRequestParametersHashModel requestParametersModel = (HttpRequestParametersHashModel) request.getAttribute( ATTR_REQUEST_PARAMETERS_MODEL); params.putUnlistedModel(KEY_REQUEST_PARAMETERS, requestParametersModel); return params; } catch (ServletException e) { throw new TemplateModelException(e); } catch (IOException e) { throw new TemplateModelException(e); } } void initializeSessionAndInstallModel(HttpServletRequest request, HttpServletResponse response, HttpSessionHashModel sessionModel, HttpSession session) throws ServletException, IOException { session.setAttribute(ATTR_SESSION_MODEL, sessionModel); initializeSession(request, response); } /** * Maps the request URL to a template path that is passed to * {@link Configuration#getTemplate(String, Locale)}. You can override it * (i.e. to provide advanced rewriting capabilities), but you are strongly * encouraged to call the overridden method first, then only modify its * return value. * @param request the currently processed request * @return a String representing the template path */ protected String requestUrlToTemplatePath(HttpServletRequest request) { // First, see if it is an included request String includeServletPath = (String) request.getAttribute("javax.servlet.include.servlet_path"); if(includeServletPath != null) { // Try path info; only if that's null (servlet is mapped to an // URL extension instead of to prefix) use servlet path. String includePathInfo = (String) request.getAttribute("javax.servlet.include.path_info"); return includePathInfo == null ? includeServletPath : includePathInfo; } // Seems that the servlet was not called as the result of a // RequestDispatcher.include(...). Try pathInfo then servletPath again, // only now directly on the request object: String path = request.getPathInfo(); if (path != null) return path; path = request.getServletPath(); if (path != null) return path; // Seems that it is a servlet mapped with prefix, and there was no extra path info. return ""; } /** * Called as the first step in request processing, before the templating mechanism * is put to work. By default does nothing and returns false. This method is * typically overridden to manage serving of non-template resources (i.e. images) * that reside in the template directory. * @param request the HTTP request * @param response the HTTP response * @return true to indicate this method has processed the request entirely, * and that the further request processing should not take place. */ protected boolean preprocessRequest( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { return false; } /** * This method is called from {@link #init()} to create the * FreeMarker configuration object that this servlet will use * for template loading. This is a hook that allows you * to custom-configure the configuration object in a subclass. * The default implementation returns a new {@link Configuration} * instance. */ protected Configuration createConfiguration() { return new Configuration(); } /** * This method is called from {@link #init()} to create the * FreeMarker object wrapper object that this servlet will use * for adapting request, session, and servlet context attributes into * template models.. This is a hook that allows you * to custom-configure the wrapper object in a subclass. * The default implementation returns a wrapper that depends on the value * of ObjectWrapper init parameter. If simple is * specified, {@link ObjectWrapper#SIMPLE_WRAPPER} is used; if jython * is specified, {@link freemarker.ext.jython.JythonWrapper} is used. In * every other case {@link ObjectWrapper#DEFAULT_WRAPPER} is used. */ protected ObjectWrapper createObjectWrapper() { String wrapper = getServletConfig().getInitParameter(DEPR_INITPARAM_OBJECT_WRAPPER); if (wrapper != null) { // BC if (getInitParameter(Configurable.OBJECT_WRAPPER_KEY) != null) { throw new RuntimeException("Conflicting init-params: " + Configurable.OBJECT_WRAPPER_KEY + " and " + DEPR_INITPARAM_OBJECT_WRAPPER); } if (DEPR_INITPARAM_WRAPPER_BEANS.equals(wrapper)) { return ObjectWrapper.BEANS_WRAPPER; } if(DEPR_INITPARAM_WRAPPER_SIMPLE.equals(wrapper)) { return ObjectWrapper.SIMPLE_WRAPPER; } if(DEPR_INITPARAM_WRAPPER_JYTHON.equals(wrapper)) { // Avoiding compile-time dependency on Jython package try { return (ObjectWrapper) Class.forName("freemarker.ext.jython.JythonWrapper") .newInstance(); } catch (InstantiationException e) { throw new InstantiationError(e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } catch (ClassNotFoundException e) { throw new NoClassDefFoundError(e.getMessage()); } } // return BeansWrapper.getDefaultInstance(); return ObjectWrapper.DEFAULT_WRAPPER; } else { wrapper = getInitParameter(Configurable.OBJECT_WRAPPER_KEY); if (wrapper == null) { // return BeansWrapper.getDefaultInstance(); return ObjectWrapper.DEFAULT_WRAPPER; } else { try { config.setSetting(Configurable.OBJECT_WRAPPER_KEY, wrapper); } catch (TemplateException e) { throw new RuntimeException(e.toString()); } return config.getObjectWrapper(); } } } protected ObjectWrapper getObjectWrapper() { return wrapper; } protected final String getTemplatePath() { return templatePath; } protected HttpRequestParametersHashModel createRequestParametersHashModel(HttpServletRequest request) { return new HttpRequestParametersHashModel(request); } /** * Called when servlet detects in a request processing that * application-global (that is, ServletContext-specific) attributes are not yet * set. * This is a generic hook you might use in subclasses to perform a specific * action on first request in the context. By default it does nothing. * @param request the actual HTTP request * @param response the actual HTTP response */ protected void initializeServletContext( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } /** * Called when servlet detects in a request processing that session-global * (that is, HttpSession-specific) attributes are not yet set. * This is a generic hook you might use in subclasses to perform a specific * action on first request in the session. By default it does nothing. It * is only invoked on newly created sessions; it is not invoked when a * replicated session is reinstantiated in another servlet container. * * @param request the actual HTTP request * @param response the actual HTTP response */ protected void initializeSession( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } /** * Called before the execution is passed to template.process(). * This is a generic hook you might use in subclasses to perform a specific * action before the template is processed. By default does nothing. * A typical action to perform here is to inject application-specific * objects into the model root * *

Example: Expose the Serlvet context path as "baseDir" for all templates: * *

     *    ((SimpleHash) data).put("baseDir", request.getContextPath() + "/");
     *    return true;
     *
* * @param request the actual HTTP request * @param response the actual HTTP response * @param template the template that will get executed * @param data the data that will be passed to the template. By default this will be * an {@link AllHttpScopesHashModel} (which is a {@link freemarker.template.SimpleHash} subclass). * Thus, you can add new variables to the data-model with the * {@link freemarker.template.SimpleHash#put(String, Object)} subclass) method. * @return true to process the template, false to suppress template processing. */ protected boolean preTemplateProcess( HttpServletRequest request, HttpServletResponse response, Template template, TemplateModel data) throws ServletException, IOException { return true; } /** * Called after the execution returns from template.process(). * This is a generic hook you might use in subclasses to perform a specific * action after the template is processed. It will be invoked even if the * template processing throws an exception. By default does nothing. * @param request the actual HTTP request * @param response the actual HTTP response * @param template the template that was executed * @param data the data that was passed to the template */ protected void postTemplateProcess( HttpServletRequest request, HttpServletResponse response, Template template, TemplateModel data) throws ServletException, IOException { } /** * Returns the {@link freemarker.template.Configuration} object used by this servlet. * Please don't forget that {@link freemarker.template.Configuration} is not thread-safe * when you modify it. */ protected Configuration getConfiguration() { return config; } /** * If the parameter "nocache" was set to true, generate a set of headers * that will advise the HTTP client not to cache the returned page. */ private void setBrowserCachingPolicy(HttpServletResponse res) { if (nocache) { // HTTP/1.1 + IE extensions res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, " + "post-check=0, pre-check=0"); // HTTP/1.0 res.setHeader("Pragma", "no-cache"); // Last resort for those that ignore all of the above res.setHeader("Expires", EXPIRATION_DATE); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/HttpRequestHashModel.java0000644000175000017500000001155711723544470027764 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.servlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; import freemarker.template.*; /** * TemplateHashModel wrapper for a HttpServletRequest attributes. * @author Attila Szegedi * @version $Id: HttpRequestHashModel.java,v 1.16 2005/05/05 07:49:58 vsajip Exp $ */ public final class HttpRequestHashModel implements TemplateHashModelEx { private final HttpServletRequest request; private final HttpServletResponse response; private final ObjectWrapper wrapper; public HttpRequestHashModel( HttpServletRequest request, ObjectWrapper wrapper) { this(request, null, wrapper); } public HttpRequestHashModel( HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper) { this.request = request; this.response = response; this.wrapper = wrapper; } public TemplateModel get(String key) throws TemplateModelException { return wrapper.wrap(request.getAttribute(key)); } public boolean isEmpty() { return !request.getAttributeNames().hasMoreElements(); } public int size() { int result = 0; for (Enumeration enumeration = request.getAttributeNames(); enumeration.hasMoreElements();) { enumeration.nextElement(); ++result; } return result; } public TemplateCollectionModel keys() { ArrayList keys = new ArrayList(); for (Enumeration enumeration = request.getAttributeNames(); enumeration.hasMoreElements();) { keys.add(enumeration.nextElement()); } return new SimpleCollection(keys.iterator()); } public TemplateCollectionModel values() { ArrayList values = new ArrayList(); for (Enumeration enumeration = request.getAttributeNames(); enumeration.hasMoreElements();) { values.add(request.getAttribute((String)enumeration.nextElement())); } return new SimpleCollection(values.iterator(), wrapper); } public HttpServletRequest getRequest() { return request; } public HttpServletResponse getResponse() { return response; } public ObjectWrapper getObjectWrapper() { return wrapper; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/HttpRequestParametersHashModel.java0000644000175000017500000001073611723544471032007 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.servlet; import freemarker.template.*; import java.util.*; import javax.servlet.http.*; /** * TemplateHashModel wrapper for a HttpServletRequest parameters. * @author Attila Szegedi * @version $Id: HttpRequestParametersHashModel.java,v 1.21 2005/05/05 07:50:25 vsajip Exp $ */ public class HttpRequestParametersHashModel implements TemplateHashModelEx { private final HttpServletRequest request; private List keys; public HttpRequestParametersHashModel(HttpServletRequest request) { this.request = request; } public TemplateModel get(String key) { String value = request.getParameter(key); return value == null ? null : new SimpleScalar(value); } public boolean isEmpty() { return !request.getParameterNames().hasMoreElements(); } public int size() { return getKeys().size(); } public TemplateCollectionModel keys() { return new SimpleCollection(getKeys().iterator()); } public TemplateCollectionModel values() { final Iterator iter = getKeys().iterator(); return new SimpleCollection( new Iterator() { public boolean hasNext() { return iter.hasNext(); } public Object next() { return request.getParameter((String)iter.next()); } public void remove() { throw new UnsupportedOperationException(); } }); } protected String transcode(String string) { return string; } private synchronized List getKeys() { if(keys == null) { keys = new ArrayList(); for (Enumeration enumeration = request.getParameterNames(); enumeration.hasMoreElements();) { keys.add(enumeration.nextElement()); } } return keys; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/ServletContextHashModel.java0000644000175000017500000001030511723544467030461 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.servlet; import javax.servlet.GenericServlet; import javax.servlet.ServletContext; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * TemplateHashModel wrapper for a ServletContext attributes. * @author Attila Szegedi * @version $Id: ServletContextHashModel.java,v 1.12 2003/01/12 23:40:14 revusky Exp $ */ public final class ServletContextHashModel implements TemplateHashModel { private final GenericServlet servlet; private final ServletContext servletctx; private final ObjectWrapper wrapper; public ServletContextHashModel( GenericServlet servlet, ObjectWrapper wrapper) { this.servlet = servlet; this.servletctx = servlet.getServletContext(); this.wrapper = wrapper; } /** * @deprecated use * {@link #ServletContextHashModel(GenericServlet, ObjectWrapper)} instead. */ public ServletContextHashModel( ServletContext servletctx, ObjectWrapper wrapper) { this.servlet = null; this.servletctx = servletctx; this.wrapper = wrapper; } public TemplateModel get(String key) throws TemplateModelException { return wrapper.wrap(servletctx.getAttribute(key)); } public boolean isEmpty() { return !servletctx.getAttributeNames().hasMoreElements(); } /** * Returns the underlying servlet. Can return null if this object was * created using the deprecated constructor. */ public GenericServlet getServlet() { return servlet; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/AllHttpScopesHashModel.java0000644000175000017500000001350311723544471030213 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.servlet; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import freemarker.template.ObjectWrapper; import freemarker.template.SimpleHash; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * An extension of SimpleHash that looks up keys in the hash, then in the * request, session, and servlet context scopes. Makes "Application", "Session" * and "Request" keys largely obsolete, however we keep them for backward * compatibility (also, "Request" is required for proper operation of JSP * taglibs). * It is on purpose that we didn't override keys and values * methods. That way, only those variables assigned into the hash directly by a * subclass of FreemarkerServlet that overrides * preTemplateProcess) are discovered as "page" variables by the FM * JSP PageContext implementation. * @author Attila Szegedi * @version $Id: AllHttpScopesHashModel.java,v 1.5.4.1 2006/04/26 12:22:07 szegedia Exp $ */ public class AllHttpScopesHashModel extends SimpleHash { private final ServletContext context; private final HttpServletRequest request; private final Map unlistedModels = new HashMap(); /** * Creates a new instance of AllHttpScopesHashModel for handling a single * HTTP servlet request. * @param wrapper the object wrapper to use * @param context the servlet context of the web application * @param request the HTTP servlet request being processed */ public AllHttpScopesHashModel(ObjectWrapper wrapper, ServletContext context, HttpServletRequest request) { setObjectWrapper(wrapper); this.context = context; this.request = request; } /** * Stores a model in the hash so that it doesn't show up in keys() * and values() methods. Used to put the Application, Session, * Request, RequestParameters and JspTaglibs objects. * @param key the key under which the model is stored * @param model the stored model */ public void putUnlistedModel(String key, TemplateModel model) { unlistedModels.put(key, model); } public TemplateModel get(String key) throws TemplateModelException { // Lookup in page scope TemplateModel model = super.get(key); if(model != null) { return model; } // Look in unlisted models model = (TemplateModel)unlistedModels.get(key); if(model != null) { return model; } // Lookup in request scope Object obj = request.getAttribute(key); if(obj != null) { return wrap(obj); } // Lookup in session scope HttpSession session = request.getSession(false); if(session != null) { obj = session.getAttribute(key); if(obj != null) { return wrap(obj); } } // Lookup in application scope obj = context.getAttribute(key); if(obj != null) { return wrap(obj); } // return wrapper's null object (probably null). return wrap(null); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/IncludePage.java0000644000175000017500000002464311723544471026070 0ustar ebourgebourgpackage freemarker.ext.servlet; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.lang.reflect.Array; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import freemarker.core.Environment; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateScalarModel; import freemarker.template.utility.Collections12; import freemarker.template.utility.DeepUnwrap; /** * A model that when invoked with a 'path' parameter will perform a servlet * include. It also support an optional hash named 'params' which specifies * request parameters for the include - its keys are strings, its values * should be either strings or sequences of strings (for multiple valued * parameters). A third optional parameter 'inherit_params' should be a boolean * when specified, and it defaults to true when not specified. A value of true * means that the include inherits the request parameters from the current * request. In this case values in 'params' will get prepended to the existing * values of parameters. * @author Attila Szegedi * @version $Id: $ */ public class IncludePage implements TemplateDirectiveModel { private final HttpServletRequest request; private final HttpServletResponse response; public IncludePage(HttpServletRequest request, HttpServletResponse response) { this.request = request; this.response = response; } public void execute(final Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // Determine the path final TemplateModel path = (TemplateModel)params.get("path"); if(path == null) { throw new TemplateException("Missing required parameter 'path'", env); } if(!(path instanceof TemplateScalarModel)) { throw new TemplateException("Expected a scalar model. 'path' is instead " + path.getClass().getName(), env); } final String strPath = ((TemplateScalarModel)path).getAsString(); if(strPath == null) { throw new TemplateException("String value of 'path' parameter is null", env); } // See whether we need to use a custom response (if we're inside a TTM // or TDM or macro nested body, we'll need to as then the current // FM environment writer is not identical to HTTP servlet response // writer. final Writer envOut = env.getOut(); final HttpServletResponse wrappedResponse; if(envOut == response.getWriter()) { // Don't bother wrapping if environment's writer is same as // response writer wrappedResponse = response; } else { final PrintWriter printWriter = (envOut instanceof PrintWriter) ? (PrintWriter)envOut : new PrintWriter(envOut); // Otherwise, create a response wrapper that will pass the // env writer, potentially first wrapping it in a print // writer when it ain't one already. wrappedResponse = new HttpServletResponseWrapper(response) { public PrintWriter getWriter() { return printWriter; } }; } // Determine inherit_params value final boolean inheritParams; final TemplateModel inheritParamsModel = (TemplateModel)params.get("inherit_params"); if(inheritParamsModel == null) { // defaults to true when not specified inheritParams = true; } else { if(!(inheritParamsModel instanceof TemplateBooleanModel)) { throw new TemplateException("'inherit_params' should be a boolean but it is " + inheritParamsModel.getClass().getName() + " instead", env); } inheritParams = ((TemplateBooleanModel)inheritParamsModel).getAsBoolean(); } // Get explicit params, if any final TemplateModel paramsModel = (TemplateModel)params.get("params"); // Determine whether we need to wrap the request final HttpServletRequest wrappedRequest; if(paramsModel == null && inheritParams) { // Inherit original request params & no params explicitly // specified, so use the original request wrappedRequest = request; } else { // In any other case, use a custom request wrapper final Map paramsMap; if(paramsModel != null) { // Convert params to a Map final Object unwrapped = DeepUnwrap.unwrap(paramsModel); if(!(unwrapped instanceof Map)) { throw new TemplateException("Expected 'params' to unwrap " + "into a java.util.Map. It unwrapped into " + unwrapped.getClass().getName() + " instead.", env); } paramsMap = (Map)unwrapped; } else { paramsMap = Collections12.EMPTY_MAP; } wrappedRequest = new CustomParamsRequest(request, paramsMap, inheritParams); } // Finally, do the include try { request.getRequestDispatcher(strPath).include(wrappedRequest, wrappedResponse); } catch (ServletException e) { throw new TemplateException(e, env); } } private static final class CustomParamsRequest extends HttpServletRequestWrapper { private final HashMap paramsMap; private CustomParamsRequest(HttpServletRequest request, Map paramMap, boolean inheritParams) { super(request); paramsMap = inheritParams ? new HashMap(request.getParameterMap()) : new HashMap(); for (Iterator it = paramMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry)it.next(); String name = String.valueOf(entry.getKey()); Object value = entry.getValue(); final String[] valueArray; if(value == null) { // Null values are explicitly added (so, among other // things, we can hide inherited param values). valueArray = new String[] { null }; } else if(value instanceof String[]) { // String[] arrays are just passed through valueArray = (String[])value; } else if(value instanceof Collection) { // Collections are converted to String[], with // String.valueOf() used on elements Collection col = (Collection)value; valueArray = new String[col.size()]; int i = 0; for (Iterator it2 = col.iterator(); it2.hasNext();) { valueArray[i++] = String.valueOf(it2.next()); } } else if(value.getClass().isArray()) { // Other array types are too converted to String[], with // String.valueOf() used on elements int len = Array.getLength(value); valueArray = new String[len]; for(int i = 0; i < len; ++i) { valueArray[i] = String.valueOf(Array.get(value, i)); } } else { // All other values (including strings) are converted to a // single-element String[], with String.valueOf applied to // the value. valueArray = new String[] { String.valueOf(value) }; } String[] existingParams = (String[])paramsMap.get(name); int el = existingParams == null ? 0 : existingParams.length; if(el == 0) { // No original params, just put our array paramsMap.put(name, valueArray); } else { int vl = valueArray.length; if(vl > 0) { // Both original params and new params, prepend our // params to original params String[] newValueArray = new String[el + vl]; System.arraycopy(valueArray, 0, newValueArray, 0, vl); System.arraycopy(existingParams, 0, newValueArray, vl, el); paramsMap.put(name, newValueArray); } } } } public String[] getParameterValues(String name) { String[] value = ((String[])paramsMap.get(name)); return value != null ? (String[])value.clone() : null; } public String getParameter(String name) { String[] values = (String[])paramsMap.get(name); return values != null && values.length > 0 ? values[0] : null; } public Enumeration getParameterNames() { return Collections.enumeration(paramsMap.keySet()); } public Map getParameterMap() { HashMap clone = (HashMap)paramsMap.clone(); for (Iterator it = clone.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry)it.next(); entry.setValue(((String[])entry.getValue()).clone()); } return Collections.unmodifiableMap(clone); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/HttpSessionHashModel.java0000644000175000017500000001370511723544471027755 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.servlet; import java.io.Serializable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * TemplateHashModel wrapper for a HttpSession attributes. * @author Attila Szegedi * @version $Id: HttpSessionHashModel.java,v 1.14.4.1 2006/04/19 16:16:43 szegedia Exp $ */ public final class HttpSessionHashModel implements TemplateHashModel, Serializable { private static final long serialVersionUID = 1L; private transient HttpSession session; private transient final ObjectWrapper wrapper; // These are required for lazy initializing session private transient final FreemarkerServlet servlet; private transient final HttpServletRequest request; private transient final HttpServletResponse response; /** * Use this constructor when the session already exists. * @param session the session * @param wrapper an object wrapper used to wrap session attributes */ public HttpSessionHashModel(HttpSession session, ObjectWrapper wrapper) { this.session = session; this.wrapper = wrapper; this.servlet = null; this.request = null; this.response = null; } /** * Use this constructor when the session isn't already created. It is passed * enough parameters so that the session can be properly initialized after * it is detected that it was created. * @param servlet the FreemarkerServlet that created this model. If the * model is not created through FreemarkerServlet, leave this argument as * null. * @param request the actual request * @param response the actual response * @param wrapper an object wrapper used to wrap session attributes */ public HttpSessionHashModel(FreemarkerServlet servlet, HttpServletRequest request, HttpServletResponse response, ObjectWrapper wrapper) { this.wrapper = wrapper; this.servlet = servlet; this.request = request; this.response = response; } public TemplateModel get(String key) throws TemplateModelException { checkSessionExistence(); return wrapper.wrap(session != null ? session.getAttribute(key) : null); } private void checkSessionExistence() throws TemplateModelException { if(session == null && request != null) { session = request.getSession(false); if(session != null && servlet != null) { try { servlet.initializeSessionAndInstallModel(request, response, this, session); } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new TemplateModelException(e); } } } } boolean isOrphaned(HttpSession currentSession) { return (session != null && session != currentSession) || (session == null && request == null); } public boolean isEmpty() throws TemplateModelException { checkSessionExistence(); return session == null || !session.getAttributeNames().hasMoreElements(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/servlet/package.html0000644000175000017500000000032211723544471025312 0ustar ebourgebourg

Provides a generic purpose servlet that generates dynamic response using FreeMarker.

@author Attila Szegedi, szegedia@freemail.hu libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/0000755000175000017500000000000012164627123022657 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonVersionAdapter.java0000644000175000017500000000661511723544470027657 0ustar ebourgebourgpackage freemarker.ext.jython; import org.python.core.PyObject; import org.python.core.PySystemState; import freemarker.template.utility.StringUtil; /** * Functions that has a different implementation depending on the Jython version * used. This was introduced to work around class-loading errors because of * different classes/methods being present in different Jython versions. */ abstract class JythonVersionAdapter { /** * Returns * obj instanceof Py[Java]Instance. */ abstract boolean isPyInstance(Object obj); /** * Returns * ((PyInstance) py[Java]Instance).__tojava__(java.lang.Object.class). */ abstract Object pyInstanceToJava(Object pyInstance); /** * Returns pyObject.__class__.__name__ */ abstract String getPythonClassName(PyObject pyObject); private static JythonVersionAdapter instance; static JythonVersionAdapter getInstance() { if (instance == null) { synchronized (JythonVersionAdapter.class) { if (instance == null) { // Note: Only the textual version number is available in Jython 2.0. int version; try { // Although PySystemState.version is present in all versions, // its type changes, so we must use reflection to get it. version = StringUtil.versionStringToInt( PySystemState.class.getField("version").get(null).toString()); } catch (Exception e) { throw new RuntimeException("Failed to get Jython version: " + e); } ClassLoader cl = JythonVersionAdapter.class.getClassLoader(); try { if (version >= 2005000) { instance = (JythonVersionAdapter) cl.loadClass( "freemarker.ext.jython.Jython25VersionAdapter") .newInstance(); } else if (version >= 2002000) { instance = (JythonVersionAdapter) cl.loadClass( "freemarker.ext.jython.Jython22VersionAdapter") .newInstance(); } else { instance = (JythonVersionAdapter) cl.loadClass( "freemarker.ext.jython.Jython20And21VersionAdapter") .newInstance(); } } catch (ClassNotFoundException e) { throw adapterCreationException(e); } catch (IllegalAccessException e) { throw adapterCreationException(e); } catch (InstantiationException e) { throw adapterCreationException(e); } } } } return instance; } private static RuntimeException adapterCreationException(Exception e) { return new RuntimeException( "Unexpected exception when creating JythonVersionAdapter: " + e); // No cause exception argument available on Java 1.2. } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonHashModel.java0000644000175000017500000001435211723544472026574 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jython; import org.python.core.PyException; import org.python.core.PyObject; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * Model for Jython dictionaries ({@link org.python.core.PyDictionary} * and {@link org.python.core.PyStringMap}). * Note that the basic {@link JythonModel} already provides access to the * {@link PyObject#__finditem__(String)} method. This class only adds * {@link TemplateHashModelEx} functionality in a somewhat skewed way. One * could say it even violates TemplateHashModelEx semantics, as both the * returned keys and values are only those from the item mapping, while the * get() method works for attributes as well. However, in practice * when you ask for dict?keys inside a template, you'll really * want to retrieve only items, not attributes so this is considered OK. * @version $Id: JythonHashModel.java,v 1.14 2003/11/12 21:53:40 ddekany Exp $ * @author Attila Szegedi */ public class JythonHashModel extends JythonModel implements TemplateHashModelEx { private static final String KEYS = "keys"; private static final String KEYSET = "keySet"; private static final String VALUES = "values"; static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new JythonHashModel((PyObject)object, (JythonWrapper)wrapper); } }; public JythonHashModel(PyObject object, JythonWrapper wrapper) { super(object, wrapper); } /** * Returns {@link PyObject#__len__()}. */ public int size() throws TemplateModelException { try { return object.__len__(); } catch(PyException e) { throw new TemplateModelException(e); } } /** * Returns either object.__findattr__("keys").__call__() * or object.__findattr__("keySet").__call__(). */ public TemplateCollectionModel keys() throws TemplateModelException { try { PyObject method = object.__findattr__(KEYS); if(method == null) { method = object.__findattr__(KEYSET); } if(method != null) { return (TemplateCollectionModel)wrapper.wrap(method.__call__()); } } catch(PyException e) { throw new TemplateModelException(e); } throw new TemplateModelException( "'?keys' is not supported as there is no 'keys' nor 'keySet' attribute on an instance of " + JythonVersionAdapter.getInstance().getPythonClassName(object)); } /** * Returns object.__findattr__("values").__call__(). */ public TemplateCollectionModel values() throws TemplateModelException { try { PyObject method = object.__findattr__(VALUES); if(method != null) { return (TemplateCollectionModel)wrapper.wrap(method.__call__()); } } catch(PyException e) { throw new TemplateModelException(e); } throw new TemplateModelException( "'?values' is not supported as there is no 'values' attribute on an instance of " + JythonVersionAdapter.getInstance().getPythonClassName(object)); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/Jython25VersionAdapter.java0000644000175000017500000000106711723544470030022 0ustar ebourgebourgpackage freemarker.ext.jython; import org.python.core.PyInstance; import org.python.core.PyObject; /** * {@link JythonVersionAdapter} for Jython 2.5. */ class Jython25VersionAdapter extends JythonVersionAdapter { boolean isPyInstance(Object obj) { return obj instanceof PyInstance; } Object pyInstanceToJava(Object pyInstance) { return ((PyInstance) pyInstance).__tojava__(java.lang.Object.class); } String getPythonClassName(PyObject pyObject) { return pyObject.getType().getName(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonSequenceModel.java0000644000175000017500000001131711723544467027463 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jython; import org.python.core.PyException; import org.python.core.PyObject; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateSequenceModel; /** * Model for Jython sequence objects ({@link org.python.core.PySequence} descendants). * @version $Id: JythonSequenceModel.java,v 1.13 2003/11/12 21:53:40 ddekany Exp $ * @author Attila Szegedi */ public class JythonSequenceModel extends JythonModel implements TemplateSequenceModel, TemplateCollectionModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new JythonSequenceModel((PyObject)object, (JythonWrapper)wrapper); } }; public JythonSequenceModel(PyObject object, JythonWrapper wrapper) { super(object, wrapper); } /** * Returns {@link PyObject#__finditem__(int)}. */ public TemplateModel get(int index) throws TemplateModelException { try { return wrapper.wrap(object.__finditem__(index)); } catch(PyException e) { throw new TemplateModelException(e); } } /** * Returns {@link PyObject#__len__()}. */ public int size() throws TemplateModelException { try { return object.__len__(); } catch(PyException e) { throw new TemplateModelException(e); } } public TemplateModelIterator iterator() { return new TemplateModelIterator() { int i = 0; public boolean hasNext() throws TemplateModelException { return i < size(); } public TemplateModel next() throws TemplateModelException { return get(i++); } }; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonWrapper.java0000644000175000017500000003174411723544470026352 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jython; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import org.python.core.Py; import org.python.core.PyDictionary; import org.python.core.PyFloat; import org.python.core.PyInteger; import org.python.core.PyLong; import org.python.core.PyObject; import org.python.core.PySequence; import org.python.core.PyString; import org.python.core.PyStringMap; import freemarker.ext.util.ModelCache; import freemarker.ext.util.WrapperTemplateModel; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelAdapter; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; import freemarker.template.utility.OptimizerUtil; /** * An object wrapper that wraps Jython objects into FreeMarker template models * and vice versa. * @version $Id: JythonWrapper.java,v 1.23.2.1 2005/10/04 16:18:08 revusky Exp $ * @author Attila Szegedi */ public class JythonWrapper implements ObjectWrapper { private static final Class PYOBJECT_CLASS = PyObject.class; public static final JythonWrapper INSTANCE = new JythonWrapper(); private final ModelCache modelCache = new JythonModelCache(this); private boolean attributesShadowItems = true; public JythonWrapper() { } /** * Sets whether this wrapper caches model instances. Default is false. * When set to true, calling {@link #wrap(Object)} multiple times for * the same object will return the same model. */ public void setUseCache(boolean useCache) { modelCache.setUseCache(useCache); } /** * Sets whether attributes shadow items in wrapped objects. When true * (this is the default value), ${object.name} will first * try to locate a python attribute with the specified name on the object * using {@link PyObject#__findattr__(java.lang.String)}, and only if it * doesn't find the attribute will it call * {@link PyObject#__getitem__(org.python.core.PyObject)}. * When set to false, the lookup order is reversed and items * are looked up before attributes. */ public synchronized void setAttributesShadowItems(boolean attributesShadowItems) { this.attributesShadowItems = attributesShadowItems; } boolean isAttributesShadowItems() { return attributesShadowItems; } /** * Wraps the passed Jython object into a FreeMarker template model. If * the object is not a Jython object, it is first coerced into one using * {@link Py#java2py(java.lang.Object)}. {@link PyDictionary} and {@link * PyStringMap} are wrapped into a hash model, {@link PySequence} * descendants are wrapped into a sequence model, {@link PyInteger}, {@link * PyLong}, and {@link PyFloat} are wrapped into a number model. All objects * are wrapped into a scalar model (using {@link Object#toString()} and a * boolean model (using {@link PyObject#__nonzero__()}. For internal * general-purpose {@link PyObject}s returned from a call to {@link * #unwrap(TemplateModel)}, the template model that was passed to * unwrap is returned. */ public TemplateModel wrap(Object obj) { if(obj == null) { return null; } return modelCache.getInstance(obj); } /** * Coerces a template model into a {@link PyObject}. * @param model the model to coerce * @return the coerced model. *
    *
  • *
  • {@link AdapterTemplateModel}s (i.e. {@link freemarker.ext.beans.BeanModel}) are marshalled * using the standard Python marshaller {@link Py#java2py(Object)} on * the result of getWrappedObject(PyObject.class)s. The * native JythonModel instances will just return the underlying PyObject. *
  • All other models that are {@link TemplateScalarModel scalars} are * marshalled as {@link PyString}. *
  • All other models that are {@link TemplateNumberModel numbers} are * marshalled using the standard Python marshaller * {@link Py#java2py(Object)} on their underlying Number
  • *
  • All other models are marshalled to a generic internal * PyObject subclass that'll correctly pass * __finditem__, __len__, * __nonzero__, and __call__ invocations to * appropriate hash, sequence, and method models.
  • *
*/ public PyObject unwrap(TemplateModel model) throws TemplateModelException { if(model instanceof AdapterTemplateModel) { return Py.java2py(((AdapterTemplateModel)model).getAdaptedObject( PYOBJECT_CLASS)); } if(model instanceof WrapperTemplateModel) { return Py.java2py(((WrapperTemplateModel)model).getWrappedObject()); } // Scalars are marshalled to PyString. if(model instanceof TemplateScalarModel) { return new PyString(((TemplateScalarModel)model).getAsString()); } // Numbers are wrapped to Python built-in numeric types. if(model instanceof TemplateNumberModel) { Number number = ((TemplateNumberModel)model).getAsNumber(); if(number instanceof BigDecimal) { number = OptimizerUtil.optimizeNumberRepresentation(number); } if(number instanceof BigInteger) { // Py.java2py can't automatically coerce a BigInteger into // a PyLong. This will probably get fixed in later Jython // release. return new PyLong((BigInteger)number); } else { return Py.java2py(number); } } // Return generic TemplateModel-to-Python adapter return new TemplateModelToJythonAdapter(model); } private class TemplateModelToJythonAdapter extends PyObject implements TemplateModelAdapter { private final TemplateModel model; TemplateModelToJythonAdapter(TemplateModel model) { this.model = model; } public TemplateModel getTemplateModel() { return model; } public PyObject __finditem__(PyObject key) { if(key instanceof PyInteger) { return __finditem__(((PyInteger)key).getValue()); } return __finditem__(key.toString()); } public PyObject __finditem__(String key) { if(model instanceof TemplateHashModel) { try { return unwrap(((TemplateHashModel)model).get(key)); } catch(TemplateModelException e) { throw Py.JavaError(e); } } throw Py.TypeError("item lookup on non-hash model (" + getModelClass() + ")"); } public PyObject __finditem__(int index) { if(model instanceof TemplateSequenceModel) { try { return unwrap(((TemplateSequenceModel)model).get(index)); } catch(TemplateModelException e) { throw Py.JavaError(e); } } throw Py.TypeError("item lookup on non-sequence model (" + getModelClass() + ")"); } public PyObject __call__(PyObject args[], String keywords[]) { if(model instanceof TemplateMethodModel) { boolean isEx = model instanceof TemplateMethodModelEx; List list = new ArrayList(args.length); try { for(int i = 0; i < args.length; ++i) { list.add( isEx ? (Object)wrap(args[i]) : (Object)( args[i] == null ? null : args[i].toString())); } return unwrap((TemplateModel) ((TemplateMethodModelEx)model).exec(list)); } catch(TemplateModelException e) { throw Py.JavaError(e); } } throw Py.TypeError("call of non-method model (" + getModelClass() + ")"); } public int __len__() { try { if(model instanceof TemplateSequenceModel) { return ((TemplateSequenceModel)model).size(); } if(model instanceof TemplateHashModelEx) { return ((TemplateHashModelEx)model).size(); } } catch(TemplateModelException e) { throw Py.JavaError(e); } return 0; } public boolean __nonzero__() { try { if(model instanceof TemplateBooleanModel) { return ((TemplateBooleanModel)model).getAsBoolean(); } if(model instanceof TemplateSequenceModel) { return ((TemplateSequenceModel)model).size() > 0; } if(model instanceof TemplateHashModel) { return !((TemplateHashModelEx)model).isEmpty(); } } catch(TemplateModelException e) { throw Py.JavaError(e); } return false; } private String getModelClass() { return model == null ? "null" : model.getClass().getName(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonModelCache.java0000644000175000017500000000563611723544472026721 0ustar ebourgebourgpackage freemarker.ext.jython; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import org.python.core.Py; import org.python.core.PyDictionary; import org.python.core.PyFloat; import org.python.core.PyInteger; import org.python.core.PyJavaInstance; import org.python.core.PyLong; import org.python.core.PyNone; import org.python.core.PyObject; import org.python.core.PySequence; import org.python.core.PyStringMap; import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.DateModel; import freemarker.ext.util.ModelCache; import freemarker.template.TemplateModel; class JythonModelCache extends ModelCache { private final JythonWrapper wrapper; JythonModelCache(JythonWrapper wrapper) { this.wrapper = wrapper; } protected boolean isCacheable(Object object) { return true; } protected TemplateModel create(Object obj) { boolean asHash = false; boolean asSequence = false; JythonVersionAdapter versionAdapter = JythonVersionAdapter.getInstance(); if(versionAdapter.isPyInstance(obj)) { Object jobj = versionAdapter.pyInstanceToJava(obj); // FreeMarker-aware, Jython-wrapped Java objects are left intact if(jobj instanceof TemplateModel) { return (TemplateModel)jobj; } if(jobj instanceof Map) { asHash = true; } if (jobj instanceof Date) { return new DateModel((Date) jobj, BeansWrapper.getDefaultInstance()); } else if(jobj instanceof Collection) { asSequence = true; // FIXME: This is an ugly hack, but AFAIK, there's no better // solution if we want to have Sets and other non-List // collections managed by this layer, as Jython quite clearly // doesn't support sets. if(!(jobj instanceof List)) { obj = new ArrayList((Collection)jobj); } } } // If it's not a PyObject, first make a PyObject out of it. if(!(obj instanceof PyObject)) { obj = Py.java2py(obj); } if(asHash || obj instanceof PyDictionary || obj instanceof PyStringMap) { return JythonHashModel.FACTORY.create(obj, wrapper); } if(asSequence || obj instanceof PySequence) { return JythonSequenceModel.FACTORY.create(obj, wrapper); } if(obj instanceof PyInteger || obj instanceof PyLong || obj instanceof PyFloat) { return JythonNumberModel.FACTORY.create(obj, wrapper); } if(obj instanceof PyNone) { return null; } return JythonModel.FACTORY.create(obj, wrapper); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonNumberModel.java0000644000175000017500000001041211723544471027131 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jython; import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyObject; import freemarker.ext.util.ModelFactory; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; /** * Model for Jython numeric objects ({@link org.python.core.PyInteger}, {@link org.python.core.PyLong}, * {@link org.python.core.PyFloat}). * @version $Id: JythonNumberModel.java,v 1.10 2003/11/12 21:53:40 ddekany Exp $ * @author Attila Szegedi */ public class JythonNumberModel extends JythonModel implements TemplateNumberModel { static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new JythonNumberModel((PyObject)object, (JythonWrapper)wrapper); } }; public JythonNumberModel(PyObject object, JythonWrapper wrapper) { super(object, wrapper); } /** * Returns either {@link PyObject#__tojava__(java.lang.Class)} with * {@link java.lang.Number}.class as argument. If that fails, returns * {@link PyObject#__float__()}. */ public Number getAsNumber() throws TemplateModelException { try { Object value = object.__tojava__(java.lang.Number.class); if(value == null || value == Py.NoConversion) { return new Double(object.__float__().getValue()); } return (Number)value; } catch(PyException e) { throw new TemplateModelException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/Jython20And21VersionAdapter.java0000644000175000017500000000111711723544470030577 0ustar ebourgebourgpackage freemarker.ext.jython; import org.python.core.PyJavaInstance; import org.python.core.PyObject; /** * {@link JythonVersionAdapter} for Jython 2.0 and 2.1. */ class Jython20And21VersionAdapter extends JythonVersionAdapter { boolean isPyInstance(Object obj) { return obj instanceof PyJavaInstance; } Object pyInstanceToJava(Object pyInstance) { return ((PyJavaInstance) pyInstance).__tojava__(java.lang.Object.class); } String getPythonClassName(PyObject pyObject) { return pyObject.__class__.__name__; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/JythonModel.java0000644000175000017500000001720011723544471025762 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jython; import java.util.Iterator; import java.util.List; import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyObject; import freemarker.ext.util.ModelFactory; import freemarker.ext.util.WrapperTemplateModel; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateScalarModel; /** * Generic model for arbitrary Jython objects. * @version $Id: JythonModel.java,v 1.14 2005/06/12 19:03:06 szegedia Exp $ * @author Attila Szegedi */ public class JythonModel implements TemplateBooleanModel, TemplateScalarModel, TemplateHashModel, TemplateMethodModelEx, AdapterTemplateModel, WrapperTemplateModel { protected final PyObject object; protected final JythonWrapper wrapper; static final ModelFactory FACTORY = new ModelFactory() { public TemplateModel create(Object object, ObjectWrapper wrapper) { return new JythonModel((PyObject)object, (JythonWrapper)wrapper); } }; public JythonModel(PyObject object, JythonWrapper wrapper) { this.object = object; this.wrapper = wrapper; } /** * Returns the value of {@link PyObject#__nonzero__()}. */ public boolean getAsBoolean() throws TemplateModelException { try { return object.__nonzero__(); } catch(PyException e) { throw new TemplateModelException(e); } } /** * Returns the value of {@link Object#toString()}. */ public String getAsString() throws TemplateModelException { try { return object.toString(); } catch(PyException e) { throw new TemplateModelException(e); } } /** * Calls {@link PyObject#__findattr__(java.lang.String)}, then if it * returns null calls {@link PyObject#__finditem__(java.lang.String)}. * If {@link JythonWrapper#setAttributesShadowItems(boolean)} was called * with false, the order of calls is reversed (that is, item * lookup takes precedence over attribute lookup). */ public TemplateModel get(String key) throws TemplateModelException { if(key != null) { key = key.intern(); } PyObject obj = null; try { if(wrapper.isAttributesShadowItems()) { obj = object.__findattr__(key); if(obj == null) { obj = object.__finditem__(key); } } else { obj = object.__finditem__(key); if(obj == null) { obj = object.__findattr__(key); } } } catch(PyException e) { throw new TemplateModelException(e); } return wrapper.wrap(obj); } /** * Returns {@link PyObject#__len__()} == 0. */ public boolean isEmpty() throws TemplateModelException { try { return object.__len__() == 0; } catch(PyException e) { throw new TemplateModelException(e); } } /** * @see freemarker.template.TemplateMethodModel#exec(List) */ public Object exec(List arguments) throws TemplateModelException { int size = arguments.size(); try { switch(size) { case 0: { return wrapper.wrap(object.__call__()); } case 1: { return wrapper.wrap(object.__call__(wrapper.unwrap( (TemplateModel)arguments.get(0)))); } default: { PyObject[] pyargs = new PyObject[size]; int i = 0; for (Iterator arg = arguments.iterator(); arg.hasNext();) { pyargs[i++] = wrapper.unwrap( (TemplateModel) arg.next()); } return wrapper.wrap(object.__call__(pyargs)); } } } catch(PyException e) { throw new TemplateModelException(e); } } public Object getAdaptedObject(Class hint) { if(object == null) { return null; } Object view = object.__tojava__(hint); if(view == Py.NoConversion) { view = object.__tojava__(Object.class); } return view; } public Object getWrappedObject() { return object == null ? null : object.__tojava__(Object.class); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/Jython22VersionAdapter.java0000644000175000017500000000110711723544470030012 0ustar ebourgebourgpackage freemarker.ext.jython; import org.python.core.PyJavaInstance; import org.python.core.PyObject; /** * {@link JythonVersionAdapter} for Jython 2.2. */ class Jython22VersionAdapter extends JythonVersionAdapter { boolean isPyInstance(Object obj) { return obj instanceof PyJavaInstance; } Object pyInstanceToJava(Object pyInstance) { return ((PyJavaInstance) pyInstance).__tojava__(java.lang.Object.class); } String getPythonClassName(PyObject pyObject) { return pyObject.getType().getFullName(); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jython/package.html0000644000175000017500000000107511723544470025146 0ustar ebourgebourg

Provides model implementations that allow access to arbitrary Jython objects.

Most of the issues dealing with Jython objects are handled by the {@link freemarker.ext.jython.JythonWrapper#wrap(Object)} method. In normal cases, this is the only method you should use to turn an arbitrary Jython object into a FreeMarker {@link freemarker.template.TemplateModel}. Additionally, you can manually create instances of any wrapper class using its constructors.

libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/0000755000175000017500000000000012164627123022140 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreemarkerTag.java0000644000175000017500000001343511723544472025535 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jsp; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTag; import javax.servlet.jsp.tagext.Tag; import freemarker.template.SimpleHash; import freemarker.template.Template; /** * Simple implementation of JSP tag to allow use of FreeMarker templates in * JSP. Inspired by similar class in Velocity template engine developed by * Geir Magnusson Jr. * @author Attila Szegedi */ public class FreemarkerTag implements BodyTag { private Tag parent; private BodyContent bodyContent; private PageContext pageContext; private SimpleHash root; private Template template; private boolean caching = true; private String name = ""; public boolean getCaching() { return caching; } public void setCaching(boolean caching) { this.caching = caching; } public void setName(String name) { this.name = name == null ? "" : name; } public Tag getParent() { return parent; } public void setParent(Tag parent) { this.parent = parent; } public int doStartTag() { return EVAL_BODY_BUFFERED; } public void setBodyContent(BodyContent bodyContent) { this.bodyContent = bodyContent; } public void setPageContext(PageContext pageContext) { this.pageContext = pageContext; root = null; } public void doInitBody() { } public int doAfterBody() { return SKIP_BODY; } public void release() { root = null; template = null; name = ""; } public int doEndTag() throws JspException { if (bodyContent == null) return EVAL_PAGE; try { if(template == null) { template = new Template(name, bodyContent.getReader()); } if(root == null) { root = new SimpleHash(); root.put("page", new JspContextModel(pageContext, JspContextModel.PAGE_SCOPE)); root.put("request", new JspContextModel(pageContext, JspContextModel.REQUEST_SCOPE)); root.put("session", new JspContextModel(pageContext, JspContextModel.SESSION_SCOPE)); root.put("application", new JspContextModel(pageContext, JspContextModel.APPLICATION_SCOPE)); root.put("any", new JspContextModel(pageContext, JspContextModel.ANY_SCOPE)); } template.process(root, pageContext.getOut()); } catch(Exception e) { try { pageContext.handlePageException(e); } catch(ServletException e2) { throw new JspException(e2.getMessage()); } catch(IOException e2) { throw new JspException(e2.getMessage()); } } finally { if(!caching) { template = null; } } return EVAL_PAGE; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/TaglibFactory.java0000644000175000017500000006711311723544471025551 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jsp; import java.beans.IntrospectionException; import java.io.ByteArrayInputStream; import java.io.FilterInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.tagext.Tag; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import freemarker.core.Environment; import freemarker.ext.servlet.FreemarkerServlet; import freemarker.ext.servlet.HttpRequestHashModel; import freemarker.log.Logger; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.StringUtil; /** * A hash model associated with a servlet context that can load JSP tag * libraries associated with that servlet context. An instance of this class is * made available in the root data model of templates executed by * {@link freemarker.ext.servlet.FreemarkerServlet} under key * JspTaglibs. It can be added to custom servlets as well to enable JSP * taglib integration in them as well. * @version $Id: TaglibFactory.java,v 1.26.2.1 2007/05/16 12:13:04 szegedia Exp $ * @author Attila Szegedi */ public class TaglibFactory implements TemplateHashModel { private static final Logger logger = Logger.getLogger("freemarker.jsp"); private static final String DEFAULT_JAR_TLD = "META-INF/taglib.tld"; // No TLDs have been looked up yet private static final int LOOKUP_NONE = 0; // Only taglibs defined in web.xml have been looked up private static final int LOOKUP_WEB_XML = 1; // Both taglibs in web.xml and those in JARs and TLD files have been looked up private static final int LOOKUP_WEB_APP = 2; private static final int ABS_URI = 0; private static final int ROOT_REL_URI = 1; private static final int NOROOT_REL_URI = 2; private final ServletContext ctx; private final Map taglibs = new HashMap(); private final Map locations = new HashMap(); private int lookupPhase = LOOKUP_NONE; /** * Creates a new JSP taglib factory that will be used to load JSP taglibs * for the web application represented by the passed servlet context. * @param ctx the servlet context whose JSP tag libraries will this factory * load. */ public TaglibFactory(ServletContext ctx) { this.ctx = ctx; } /** * Retrieves a JSP tag library identified by an URI. The matching of the URI * to a JSP taglib is done as described in the JSP 1.2 FCS specification. * @param uri the URI that describes the JSP taglib. It can be any of the * three forms allowed by the JSP specification: absolute URI, root relative * URI and non-root relative URI. Note that if a non-root relative URI is * used it is resolved relative to the URL of the current request. In this * case, the current request is obtained by looking up a * {@link HttpRequestHashModel} object named Request in the root * data model. FreemarkerServlet provides this object under the expected * name, and custom servlets that want to integrate JSP taglib support * should do the same. * @return a hash model representing the JSP taglib. Each element of this * hash model represents a single custom tag from the library, implemented * as a {@link freemarker.template.TemplateTransformModel}. */ public TemplateModel get(String uri) throws TemplateModelException { synchronized (taglibs) { final Taglib taglib = (Taglib) taglibs.get(uri); if(taglib != null) { return taglib; } try { // Make sure we have mappings from at least web.xml if(lookupPhase == LOOKUP_NONE) { addLocationsFromWebXml(); lookupPhase = LOOKUP_WEB_XML; } // Try explicit mapping TldPath path = (TldPath)locations.get(uri); if(path != null) { return loadTaglib(path, uri); } // Make sure we have mappings from .jar and .tld files, too. // Note that this delays scanning the WEB-INF directory as long // as taglibs can be found based on web.xml mapping. if(lookupPhase == LOOKUP_WEB_XML) { addLocationsFromWebApp(); lookupPhase = LOOKUP_WEB_APP; // Try newly found explicit mappings path = (TldPath)locations.get(uri); if(path != null) { return loadTaglib(path, uri); } } // No mappings found, try treating the path as explicit path switch(getUriType(uri)) { case ABS_URI: { // Absolute URIs can only be resolved through mapping throw new TemplateModelException("No mapping defined for " + uri); } case NOROOT_REL_URI: { // Resolve URI relative to the current page uri = resolveRelativeUri(uri); // Intentional fallthrough } case ROOT_REL_URI: { // If it is a .jar or .zip, add default TLD entry within it. if(uri.endsWith(".jar") || uri.endsWith(".zip")) { return loadTaglib(new TldPath(uri, DEFAULT_JAR_TLD), uri); } // Treat the URI verbatim. return loadTaglib(new TldPath(uri), uri); } default: { throw new RuntimeException("Cannot happen"); } } } catch(TemplateModelException e) { throw e; } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new TemplateModelException("Could not load taglib information for " + uri, e); } } } private static class TldPath { final String filePath; final String jarItemPath; TldPath(String filePath) { this(filePath, null); } TldPath(String filePath, String jarItemPath) { this.filePath = filePath; this.jarItemPath = jarItemPath; } public String toString() { if(jarItemPath == null) { return filePath; } return filePath + "!" + jarItemPath; } } private TemplateModel loadTaglib(TldPath tldPath, String uri) throws Exception { if(logger.isDebugEnabled()) { logger.debug("Loading taglib " + StringUtil.jQuoteNoXSS(uri) + " from location " + StringUtil.jQuoteNoXSS(tldPath)); } final Taglib taglib = new Taglib(ctx, tldPath, uri); taglibs.put(uri, taglib); locations.remove(uri); return taglib; } private static int getUriType(String uri) throws TemplateModelException { if(uri == null) { throw new TemplateModelException("null is not a valid URI"); } if(uri.length() == 0) { throw new TemplateModelException("empty string is not a valid URI"); } final char c0 = uri.charAt(0); if(c0 == '/') { return ROOT_REL_URI; } // Check if it conforms to RFC 3986 3.1 in order to qualify as ABS_URI if(c0 < 'a' || c0 > 'z') { // First char of scheme must be alpha return NOROOT_REL_URI; } final int colon = uri.indexOf(':'); if(colon == -1) { // Must have a colon return NOROOT_REL_URI; } // Subsequent chars must be [a-z,0-9,+,-,.] for(int i = 1; i < colon; ++i) { final char c = uri.charAt(i); if((c < 'a' || c > 'z') && (c < '0' || c > '9') && c != '+' && c != '-' && c != '.') { return NOROOT_REL_URI; } } return ABS_URI; } /** * Returns false. */ public boolean isEmpty() { return false; } private void addLocationsFromWebXml() throws Exception { WebXmlParser webXmlParser = new WebXmlParser(); InputStream in = ctx.getResourceAsStream("/WEB-INF/web.xml"); if (in == null) { // No /WEB-INF/web.xml - do nothing return; } try { parseXml(in, ctx.getResource("/WEB-INF/web.xml").toExternalForm(), webXmlParser); } finally { in.close(); } } private class WebXmlParser extends DefaultHandler { private StringBuffer buf; private String uri; private String location; private Locator locator; public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startElement( String nsuri, String localName, String qName, Attributes atts) { if ("taglib-uri".equals(qName) || "taglib-location".equals(qName)) { buf = new StringBuffer(); } } public void characters(char[] chars, int off, int len) { if (buf != null) { buf.append(chars, off, len); } } public void endElement(String nsuri, String localName, String qName) throws SAXParseException { if ("taglib-uri".equals(qName)) { uri = buf.toString().trim(); buf = null; } else if ("taglib-location".equals(qName)) { location = buf.toString().trim(); try { if(getUriType(location) == NOROOT_REL_URI) { location = "/WEB-INF/" + location; } } catch(TemplateModelException e) { throw new SAXParseException(e.getMessage(), locator, e); } buf = null; } else if ("taglib".equals(qName)) { final String zname; if(location.endsWith(".jar") || location.endsWith(".zip")) { zname = DEFAULT_JAR_TLD; } else { zname = null; } addLocation("web.xml", location, zname, uri); } } } private void addLocationsFromWebApp() throws Exception { Set libs = ctx.getResourcePaths("/WEB-INF/lib"); if (libs != null) { for (Iterator iter = libs.iterator(); iter.hasNext();) { String path = (String) iter.next(); if(path.endsWith(".jar") || path.endsWith(".zip")) { addLocationsFromJarFile(path); } else if(path.endsWith(".tld")) { addLocationFromTldFile(path); } } } libs = ctx.getResourcePaths("/WEB-INF"); if (libs != null) { for (Iterator iter = libs.iterator(); iter.hasNext();) { String path = (String) iter.next(); if(path.endsWith(".tld")) { addLocationFromTldFile(path); } } } } private void addLocationsFromJarFile(String path) throws Exception { ZipInputStream zin = new ZipInputStream(ctx.getResourceAsStream(path)); // Make stream uncloseable by XML parsers InputStream uin = new FilterInputStream(zin) { public void close() { } }; try { for(;;) { ZipEntry ze = zin.getNextEntry(); if(ze == null) { break; } String zname = ze.getName(); if(zname.startsWith("META-INF/") && zname.endsWith(".tld")) { String url = "jar:" + ctx.getResource(path).toExternalForm() + "!" + zname; addLocationFromTldResource(uin, path, zname, url); } } } finally { zin.close(); } } private void addLocationFromTldFile(String path) throws Exception { InputStream in = ctx.getResourceAsStream(path); try { addLocationFromTldResource(in, path, null, ctx.getResource(path).toExternalForm()); } finally { in.close(); } } private void addLocationFromTldResource(InputStream uin, String path, String zname, String url) throws Exception { String uri = getTldUri(uin, url); if(uri != null) { addLocation(zname == null ? "tld file" : "jar file", path, zname, uri); } } private void addLocation(String source, String filePath, String jarItemPath, String uri) { final TldPath tldPath = new TldPath(filePath, jarItemPath); if(locations.containsKey(uri)) { logger.debug("Ignored duplicate URI " + StringUtil.jQuoteNoXSS(uri) + " in " + source + " " + StringUtil.jQuoteNoXSS(tldPath)); } else { locations.put(uri, tldPath); if(logger.isDebugEnabled()) { logger.debug(source + " assigned URI " + StringUtil.jQuoteNoXSS(uri) + " to location " + StringUtil.jQuoteNoXSS(tldPath)); } } } private String getTldUri(InputStream in, String url) throws Exception { TldUriReader tur = new TldUriReader(); parseXml(in, url, tur); return tur.getUri(); } private static class TldUriReader extends DefaultHandler { private StringBuffer buf; private String uri; TldUriReader() { } String getUri() { return uri; } public void startElement( String nsuri, String localName, String qName, Attributes atts) { if ("uri".equals(qName)) { buf = new StringBuffer(); } } public void characters(char[] chars, int off, int len) { if (buf != null) { buf.append(chars, off, len); } } public void endElement(String nsuri, String localName, String qName) { if ("uri".equals(qName)) { uri = buf.toString().trim(); buf = null; } } } private static void parseXml(InputStream in, String url, DefaultHandler handler) throws Exception { InputSource is = new InputSource(); is.setByteStream(in); is.setSystemId(url); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(false); factory.setValidating(false); XMLReader reader = factory.newSAXParser().getXMLReader(); reader.setEntityResolver(new LocalTaglibDtds()); reader.setContentHandler(handler); reader.setErrorHandler(handler); reader.parse(is); } private static final class Taglib implements TemplateHashModel { private final Map tags; Taglib(ServletContext ctx, TldPath tldPath, String uri) throws Exception { tags = loadTaglib(ctx, tldPath, uri); } public TemplateModel get(String key) { return (TemplateModel)tags.get(key); } public boolean isEmpty() { return tags.isEmpty(); } private static final Map loadTaglib(ServletContext ctx, TldPath tldPath, String uri) throws Exception { final TldParser tldParser = new TldParser(); final String filePath = tldPath.filePath; final InputStream in = ctx.getResourceAsStream(filePath); if(in == null) { throw new TemplateModelException("Could not find webapp resource " + filePath + " for URI " + uri); } final String fileUrl = ctx.getResource(filePath).toExternalForm(); try { final String jarItemPath = tldPath.jarItemPath; if(jarItemPath != null) { final ZipInputStream zin = new ZipInputStream(in); for(;;) { final ZipEntry ze = zin.getNextEntry(); if(ze == null) { throw new TemplateModelException( "Could not find JAR entry " + jarItemPath + " inside webapp resource " + filePath + " for URI " + uri); } final String zname = ze.getName(); if(zname.equals(jarItemPath)) { parseXml(zin, "jar:" + fileUrl + "!" + zname, tldParser); break; } } } else { parseXml(in, fileUrl, tldParser); } } finally { in.close(); } EventForwarding eventForwarding = EventForwarding.getInstance(ctx); if(eventForwarding != null) { eventForwarding.addListeners(tldParser.getListeners()); } else if(tldParser.getListeners().size() > 0) { throw new TemplateModelException( "Event listeners specified in the TLD could not be " + " registered since the web application doesn't have a" + " listener of class " + EventForwarding.class.getName() + ". To remedy this, add this element to web.xml:\n" + "| \n" + "| " + EventForwarding.class.getName() + "\n" + "| "); } return tldParser.getTags(); } } private static String resolveRelativeUri(String uri) throws TemplateModelException { TemplateModel reqHash = Environment.getCurrentEnvironment().getVariable( FreemarkerServlet.KEY_REQUEST_PRIVATE); if(reqHash instanceof HttpRequestHashModel) { HttpServletRequest req = ((HttpRequestHashModel)reqHash).getRequest(); String pi = req.getPathInfo(); String reqPath = req.getServletPath(); if(reqPath == null) { reqPath = ""; } reqPath += (pi == null ? "" : pi); // We don't care about paths with ".." in them. If the container // wishes to resolve them on its own, let it be. int lastSlash = reqPath.lastIndexOf('/'); if(lastSlash != -1) { return reqPath.substring(0, lastSlash + 1) + uri; } else { return '/' + uri; } } throw new TemplateModelException( "Can't resolve relative URI " + uri + " as request URL information is unavailable."); } private static final class TldParser extends DefaultHandler { private final Map tags = new HashMap(); private final List listeners = new ArrayList(); private Locator locator; private StringBuffer buf; private String tagName; private String tagClassName; Map getTags() { return tags; } List getListeners() { return listeners; } public void setDocumentLocator(Locator locator) { this.locator = locator; } public void startElement( String nsuri, String localName, String qName, Attributes atts) { if ("name".equals(qName) || "tagclass".equals(qName) || "tag-class".equals(qName) || "listener-class".equals(qName)) { buf = new StringBuffer(); } } public void characters(char[] chars, int off, int len) { if (buf != null) { buf.append(chars, off, len); } } public void endElement(String nsuri, String localName, String qName) throws SAXParseException { if ("name".equals(qName)) { if(tagName == null) { tagName = buf.toString().trim(); } buf = null; } else if ("tagclass".equals(qName) || "tag-class".equals(qName)) { tagClassName = buf.toString().trim(); buf = null; } else if ("tag".equals(qName)) { try { Class tagClass = ClassUtil.forName(tagClassName); TemplateModel impl; if(Tag.class.isAssignableFrom(tagClass)) { impl = new TagTransformModel(tagClass); } else { impl = new SimpleTagDirectiveModel(tagClass); } tags.put(tagName, impl); tagName = null; tagClassName = null; } catch (IntrospectionException e) { throw new SAXParseException( "Can't introspect tag class " + tagClassName, locator, e); } catch (ClassNotFoundException e) { throw new SAXParseException( "Can't find tag class " + tagClassName, locator, e); } } else if ("listener-class".equals(qName)) { String listenerClass = buf.toString().trim(); buf = null; try { listeners.add(ClassUtil.forName(listenerClass).newInstance()); } catch(Exception e) { throw new SAXParseException( "Can't instantiate listener class " + listenerClass, locator, e); } } } } private static final Map dtds = new HashMap(); static { // JSP taglib 2.1 dtds.put("http://java.sun.com/xml/ns/jee/web-jsptaglibrary_2_1.xsd", "web-jsptaglibrary_2_1.xsd"); // JSP taglib 2.0 dtds.put("http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd", "web-jsptaglibrary_2_0.xsd"); // JSP taglib 1.2 dtds.put("-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN", "web-jsptaglibrary_1_2.dtd"); dtds.put("http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd", "web-jsptaglibrary_1_2.dtd"); // JSP taglib 1.1 dtds.put("-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN", "web-jsptaglibrary_1_1.dtd"); dtds.put("http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd", "web-jsptaglibrary_1_1.dtd"); // Servlet 2.5 dtds.put("http://java.sun.com/xml/ns/jee/web-app_2_5.xsd", "web-app_2_5.xsd"); // Servlet 2.4 dtds.put("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", "web-app_2_4.xsd"); // Servlet 2.3 dtds.put("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN", "web-app_2_3.dtd"); dtds.put("http://java.sun.com/dtd/web-app_2_3.dtd", "web-app_2_3.dtd"); // Servlet 2.2 dtds.put("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", "web-app_2_2.dtd"); dtds.put("http://java.sun.com/j2ee/dtds/web-app_2_2.dtd", "web-app_2_2.dtd"); } private static final class LocalTaglibDtds implements EntityResolver { public InputSource resolveEntity(String publicId, String systemId) { String resourceName = (String)dtds.get(publicId); if(resourceName == null) { resourceName = (String)dtds.get(systemId); } InputStream resourceStream; if(resourceName != null) { resourceStream = getClass().getResourceAsStream(resourceName); } else { // Fake an empty stream for unknown DTDs resourceStream = new ByteArrayInputStream(new byte[0]); } InputSource is = new InputSource(); is.setPublicId(publicId); is.setSystemId(systemId); is.setByteStream(resourceStream); return is; } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/JspWriterAdapter.java0000644000175000017500000000665011723544471026250 0ustar ebourgebourg/** * */ package freemarker.ext.jsp; import java.io.IOException; import java.io.Writer; import javax.servlet.jsp.JspWriter; import freemarker.template.utility.SecurityUtilities; class JspWriterAdapter extends JspWriter { static final char[] NEWLINE = SecurityUtilities.getSystemProperty("line.separator").toCharArray(); private final Writer out; JspWriterAdapter(Writer out) { super(0, true); this.out = out; } public String toString() { return "JspWriterAdapter wrapping a " + out.toString(); } public void clear() throws IOException { throw new IOException("Can't clear"); } public void clearBuffer() throws IOException { throw new IOException("Can't clear"); } public void close() throws IOException { throw new IOException("Close not permitted."); } public void flush() throws IOException { out.flush(); } public int getRemaining() { return 0; } public void newLine() throws IOException { out.write(NEWLINE); } public void print(boolean arg0) throws IOException { out.write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); } public void print(char arg0) throws IOException { out.write(arg0); } public void print(char[] arg0) throws IOException { out.write(arg0); } public void print(double arg0) throws IOException { out.write(Double.toString(arg0)); } public void print(float arg0) throws IOException { out.write(Float.toString(arg0)); } public void print(int arg0) throws IOException { out.write(Integer.toString(arg0)); } public void print(long arg0) throws IOException { out.write(Long.toString(arg0)); } public void print(Object arg0) throws IOException { out.write(arg0 == null ? "null" : arg0.toString()); } public void print(String arg0) throws IOException { out.write(arg0); } public void println() throws IOException { newLine(); } public void println(boolean arg0) throws IOException { print(arg0); newLine(); } public void println(char arg0) throws IOException { print(arg0); newLine(); } public void println(char[] arg0) throws IOException { print(arg0); newLine(); } public void println(double arg0) throws IOException { print(arg0); newLine(); } public void println(float arg0) throws IOException { print(arg0); newLine(); } public void println(int arg0) throws IOException { print(arg0); newLine(); } public void println(long arg0) throws IOException { print(arg0); newLine(); } public void println(Object arg0) throws IOException { print(arg0); newLine(); } public void println(String arg0) throws IOException { print(arg0); newLine(); } public void write(int c) throws IOException { out.write(c); } public void write(char[] arg0, int arg1, int arg2) throws IOException { out.write(arg0, arg1, arg2); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerPageContext.java0000644000175000017500000004225011723544471027177 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jsp; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.ListIterator; import javax.servlet.GenericServlet; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import javax.servlet.http.HttpSession; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyContent; import freemarker.core.Environment; import freemarker.ext.servlet.FreemarkerServlet; import freemarker.ext.servlet.HttpRequestHashModel; import freemarker.ext.servlet.ServletContextHashModel; import freemarker.ext.util.WrapperTemplateModel; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.utility.UndeclaredThrowableException; /** * @version $Id: FreeMarkerPageContext.java,v 1.26.2.2 2006/07/08 14:45:34 ddekany Exp $ * @author Attila Szegedi */ abstract class FreeMarkerPageContext extends PageContext implements TemplateModel { private static final Class OBJECT_CLASS = Object.class; private final Environment environment; private List tags = new ArrayList(); private List outs = new ArrayList(); private final GenericServlet servlet; private HttpSession session; private final HttpServletRequest request; private final HttpServletResponse response; private final ObjectWrapper wrapper; private JspWriter jspOut; protected FreeMarkerPageContext() throws TemplateModelException { environment = Environment.getCurrentEnvironment(); TemplateModel appModel = environment.getGlobalVariable( FreemarkerServlet.KEY_APPLICATION_PRIVATE); if(!(appModel instanceof ServletContextHashModel)) { appModel = environment.getGlobalVariable( FreemarkerServlet.KEY_APPLICATION); } if(appModel instanceof ServletContextHashModel) { this.servlet = ((ServletContextHashModel)appModel).getServlet(); } else { throw new TemplateModelException("Could not find an instance of " + ServletContextHashModel.class.getName() + " in the data model under either the name " + FreemarkerServlet.KEY_APPLICATION_PRIVATE + " or " + FreemarkerServlet.KEY_APPLICATION); } TemplateModel requestModel = environment.getGlobalVariable(FreemarkerServlet.KEY_REQUEST_PRIVATE); if(!(requestModel instanceof HttpRequestHashModel)) { requestModel = environment.getGlobalVariable( FreemarkerServlet.KEY_REQUEST); } if(requestModel instanceof HttpRequestHashModel) { HttpRequestHashModel reqHash = (HttpRequestHashModel)requestModel; this.request = reqHash.getRequest(); this.session = request.getSession(false); this.response = reqHash.getResponse(); this.wrapper = reqHash.getObjectWrapper(); } else { throw new TemplateModelException("Could not find an instance of " + HttpRequestHashModel.class.getName() + " in the data model under either the name " + FreemarkerServlet.KEY_REQUEST_PRIVATE + " or " + FreemarkerServlet.KEY_REQUEST); } // Register page attributes as per spec setAttribute(REQUEST, request); setAttribute(RESPONSE, response); if (session != null) setAttribute(SESSION, session); setAttribute(PAGE, servlet); setAttribute(CONFIG, servlet.getServletConfig()); setAttribute(PAGECONTEXT, this); setAttribute(APPLICATION, servlet.getServletContext()); } ObjectWrapper getObjectWrapper() { return wrapper; } public void initialize( Servlet servlet, ServletRequest request, ServletResponse response, String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) { throw new UnsupportedOperationException(); } public void release() { } public void setAttribute(String name, Object value) { setAttribute(name, value, PAGE_SCOPE); } public void setAttribute(String name, Object value, int scope) { switch(scope) { case PAGE_SCOPE: { try { environment.setGlobalVariable(name, wrapper.wrap(value)); break; } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } case REQUEST_SCOPE: { getRequest().setAttribute(name, value); break; } case SESSION_SCOPE: { getSession(true).setAttribute(name, value); break; } case APPLICATION_SCOPE: { getServletContext().setAttribute(name, value); break; } default: { throw new IllegalArgumentException("Invalid scope " + scope); } } } public Object getAttribute(String name) { return getAttribute(name, PAGE_SCOPE); } public Object getAttribute(String name, int scope) { switch (scope) { case PAGE_SCOPE: { try { TemplateModel m = environment.getGlobalNamespace().get(name); if (m instanceof AdapterTemplateModel) { return ((AdapterTemplateModel) m).getAdaptedObject(OBJECT_CLASS); } if (m instanceof WrapperTemplateModel) { return ((WrapperTemplateModel)m).getWrappedObject(); } if (m instanceof TemplateScalarModel) { return ((TemplateScalarModel) m).getAsString(); } if (m instanceof TemplateNumberModel) { return ((TemplateNumberModel) m).getAsNumber(); } if (m instanceof TemplateBooleanModel) { return ((TemplateBooleanModel) m).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; } return m; } catch (TemplateModelException e) { throw new UndeclaredThrowableException(e); } } case REQUEST_SCOPE: { return getRequest().getAttribute(name); } case SESSION_SCOPE: { HttpSession session = getSession(false); if(session == null) { return null; } return session.getAttribute(name); } case APPLICATION_SCOPE: { return getServletContext().getAttribute(name); } default: { throw new IllegalArgumentException("Invalid scope " + scope); } } } public Object findAttribute(String name) { Object retval = getAttribute(name, PAGE_SCOPE); if(retval != null) return retval; retval = getAttribute(name, REQUEST_SCOPE); if(retval != null) return retval; retval = getAttribute(name, SESSION_SCOPE); if(retval != null) return retval; return getAttribute(name, APPLICATION_SCOPE); } public void removeAttribute(String name) { removeAttribute(name, PAGE_SCOPE); removeAttribute(name, REQUEST_SCOPE); removeAttribute(name, SESSION_SCOPE); removeAttribute(name, APPLICATION_SCOPE); } public void removeAttribute(String name, int scope) { switch(scope) { case PAGE_SCOPE: { environment.getGlobalNamespace().remove(name); break; } case REQUEST_SCOPE: { getRequest().removeAttribute(name); break; } case SESSION_SCOPE: { HttpSession session = getSession(false); if(session != null) { session.removeAttribute(name); } break; } case APPLICATION_SCOPE: { getServletContext().removeAttribute(name); break; } default: { throw new IllegalArgumentException("Invalid scope: " + scope); } } } public int getAttributesScope(String name) { if(getAttribute(name, PAGE_SCOPE) != null) return PAGE_SCOPE; if(getAttribute(name, REQUEST_SCOPE) != null) return REQUEST_SCOPE; if(getAttribute(name, SESSION_SCOPE) != null) return SESSION_SCOPE; if(getAttribute(name, APPLICATION_SCOPE) != null) return APPLICATION_SCOPE; return 0; } public Enumeration getAttributeNamesInScope(int scope) { switch(scope) { case PAGE_SCOPE: { try { return new TemplateHashModelExEnumeration(environment.getGlobalNamespace()); } catch(TemplateModelException e) { throw new UndeclaredThrowableException(e); } } case REQUEST_SCOPE: { return getRequest().getAttributeNames(); } case SESSION_SCOPE: { HttpSession session = getSession(false); if(session != null) { return session.getAttributeNames(); } return Collections.enumeration(Collections.EMPTY_SET); } case APPLICATION_SCOPE: { return getServletContext().getAttributeNames(); } default: { throw new IllegalArgumentException("Invalid scope " + scope); } } } public JspWriter getOut() { return jspOut; } private HttpSession getSession(boolean create) { if(session == null) { session = request.getSession(create); if(session != null) { setAttribute(SESSION, session); } } return session; } public HttpSession getSession() { return getSession(false); } public Object getPage() { return servlet; } public ServletRequest getRequest() { return request; } public ServletResponse getResponse() { return response; } public Exception getException() { throw new UnsupportedOperationException(); } public ServletConfig getServletConfig() { return servlet.getServletConfig(); } public ServletContext getServletContext() { return servlet.getServletContext(); } public void forward(String url) throws ServletException, IOException { //TODO: make sure this is 100% correct by looking at Jasper output request.getRequestDispatcher(url).forward(request, response); } public void include(String url) throws ServletException, IOException { jspOut.flush(); request.getRequestDispatcher(url).include(request, response); } public void include(String url, boolean flush) throws ServletException, IOException { if(flush) { jspOut.flush(); } final PrintWriter pw = new PrintWriter(jspOut); request.getRequestDispatcher(url).include(request, new HttpServletResponseWrapper(response) { public PrintWriter getWriter() { return pw; } public ServletOutputStream getOutputStream() { throw new UnsupportedOperationException("JSP-included resource must use getWriter()"); } }); pw.flush(); } public void handlePageException(Exception e) { throw new UnsupportedOperationException(); } public void handlePageException(Throwable e) { throw new UnsupportedOperationException(); } public BodyContent pushBody() { return (BodyContent)pushWriter(new TagTransformModel.BodyContentImpl(getOut(), true)); } public JspWriter pushBody(Writer w) { return pushWriter(new JspWriterAdapter(w)); } public JspWriter popBody() { popWriter(); return (JspWriter) getAttribute(OUT); } Object peekTopTag(Class tagClass) { for (ListIterator iter = tags.listIterator(tags.size()); iter.hasPrevious();) { Object tag = iter.previous(); if(tagClass.isInstance(tag)) { return tag; } } return null; } void popTopTag() { tags.remove(tags.size() - 1); } void popWriter() { jspOut = (JspWriter)outs.remove(outs.size() - 1); setAttribute(OUT, jspOut); } void pushTopTag(Object tag) { tags.add(tag); } JspWriter pushWriter(JspWriter out) { outs.add(jspOut); jspOut = out; setAttribute(OUT, jspOut); return out; } private static class TemplateHashModelExEnumeration implements Enumeration { private final TemplateModelIterator it; private TemplateHashModelExEnumeration(TemplateHashModelEx hashEx) throws TemplateModelException { it = hashEx.keys().iterator(); } public boolean hasMoreElements() { try { return it.hasNext(); } catch (TemplateModelException tme) { throw new UndeclaredThrowableException(tme); } } public Object nextElement() { try { return ((TemplateScalarModel) it.next()).getAsString(); } catch (TemplateModelException tme) { throw new UndeclaredThrowableException(tme); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerJspFactory.java0000644000175000017500000000307511723544472027045 0ustar ebourgebourgpackage freemarker.ext.jsp; import javax.servlet.Servlet; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.jsp.JspEngineInfo; import javax.servlet.jsp.JspFactory; import javax.servlet.jsp.PageContext; /** * @author Attila Szegedi * @version $Id: $ */ abstract class FreeMarkerJspFactory extends JspFactory { protected abstract String getSpecificationVersion(); public JspEngineInfo getEngineInfo() { return new JspEngineInfo() { public String getSpecificationVersion() { return FreeMarkerJspFactory.this.getSpecificationVersion(); } }; } public PageContext getPageContext(Servlet servlet, ServletRequest request, ServletResponse response, String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) { // This is never meant to be called. JSP pages compiled to Java // bytecode use this API, but in FreeMarker, we're running templates, // and not JSP pages precompiled to bytecode, therefore we have no use // for this API. throw new UnsupportedOperationException(); } public void releasePageContext(PageContext ctx) { // This is never meant to be called. JSP pages compiled to Java // bytecode use this API, but in FreeMarker, we're running templates, // and not JSP pages precompiled to bytecode, therefore we have no use // for this API. throw new UnsupportedOperationException(); } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerJspApplicationContext.java0000644000175000017500000001220211723544471031235 0ustar ebourgebourgpackage freemarker.ext.jsp; import java.util.Iterator; import java.util.LinkedList; import javax.el.ArrayELResolver; import javax.el.BeanELResolver; import javax.el.CompositeELResolver; import javax.el.ELContext; import javax.el.ELContextEvent; import javax.el.ELContextListener; import javax.el.ELResolver; import javax.el.ExpressionFactory; import javax.el.FunctionMapper; import javax.el.ListELResolver; import javax.el.MapELResolver; import javax.el.ResourceBundleELResolver; import javax.el.ValueExpression; import javax.el.VariableMapper; import javax.servlet.jsp.JspApplicationContext; import javax.servlet.jsp.el.ImplicitObjectELResolver; import javax.servlet.jsp.el.ScopedAttributeELResolver; import freemarker.log.Logger; import freemarker.template.utility.ClassUtil; /** * @author Attila Szegedi * @version $Id: $ */ class FreeMarkerJspApplicationContext implements JspApplicationContext { private static final Logger logger = Logger.getLogger("freemarker.jsp"); private static final ExpressionFactory expressionFactoryImpl = findExpressionFactoryImplementation(); private final LinkedList listeners = new LinkedList(); private final CompositeELResolver elResolver = new CompositeELResolver(); private final CompositeELResolver additionalResolvers = new CompositeELResolver(); { elResolver.add(new ImplicitObjectELResolver()); elResolver.add(additionalResolvers); elResolver.add(new MapELResolver()); elResolver.add(new ResourceBundleELResolver()); elResolver.add(new ListELResolver()); elResolver.add(new ArrayELResolver()); elResolver.add(new BeanELResolver()); elResolver.add(new ScopedAttributeELResolver()); } public void addELContextListener(ELContextListener listener) { synchronized(listeners) { listeners.addLast(listener); } } private static ExpressionFactory findExpressionFactoryImplementation() { ExpressionFactory ef = tryExpressionFactoryImplementation("com.sun"); if(ef == null) { ef = tryExpressionFactoryImplementation("org.apache"); if(ef == null) { logger.warn("Could not find any implementation for " + ExpressionFactory.class.getName()); } } return ef; } private static ExpressionFactory tryExpressionFactoryImplementation(String packagePrefix) { String className = packagePrefix + ".el.ExpressionFactoryImpl"; try { Class cl = ClassUtil.forName(className); if(ExpressionFactory.class.isAssignableFrom(cl)) { logger.info("Using " + className + " as implementation of " + ExpressionFactory.class.getName()); return (ExpressionFactory)cl.newInstance(); } logger.warn("Class " + className + " does not implement " + ExpressionFactory.class.getName()); } catch(ClassNotFoundException e) { } catch(Exception e) { logger.error("Failed to instantiate " + className, e); } return null; } public void addELResolver(ELResolver resolver) { additionalResolvers.add(resolver); } public ExpressionFactory getExpressionFactory() { return expressionFactoryImpl; } ELContext createNewELContext(final FreeMarkerPageContext pageCtx) { ELContext ctx = new FreeMarkerELContext(pageCtx); ELContextEvent event = new ELContextEvent(ctx); synchronized(listeners) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { ELContextListener l = (ELContextListener) iter.next(); l.contextCreated(event); } } return ctx; } private class FreeMarkerELContext extends ELContext { private final FreeMarkerPageContext pageCtx; FreeMarkerELContext(FreeMarkerPageContext pageCtx) { this.pageCtx = pageCtx; } public ELResolver getELResolver() { return elResolver; } public FunctionMapper getFunctionMapper() { return null; } public VariableMapper getVariableMapper() { return new VariableMapper() { public ValueExpression resolveVariable(String name) { Object obj = pageCtx.findAttribute(name); if(obj == null) { return null; } return expressionFactoryImpl.createValueExpression(obj, obj.getClass()); } public ValueExpression setVariable(String name, ValueExpression value) { ValueExpression prev = resolveVariable(name); pageCtx.setAttribute(name, value.getValue( FreeMarkerELContext.this)); return prev; } }; } } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/JspContextModel.java0000644000175000017500000000727411723544471026103 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jsp; import javax.servlet.jsp.PageContext; import freemarker.ext.beans.BeansWrapper; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; class JspContextModel implements TemplateHashModel { public static final int ANY_SCOPE = -1; public static final int PAGE_SCOPE = PageContext.PAGE_SCOPE; public static final int REQUEST_SCOPE = PageContext.REQUEST_SCOPE; public static final int SESSION_SCOPE = PageContext.SESSION_SCOPE; public static final int APPLICATION_SCOPE = PageContext.APPLICATION_SCOPE; private final PageContext pageContext; private final int scope; public JspContextModel(PageContext pageContext, int scope) { this.pageContext = pageContext; this.scope = scope; } public TemplateModel get(String key) throws TemplateModelException { Object bean = scope == ANY_SCOPE ? pageContext.findAttribute(key) : pageContext.getAttribute(key, scope); return BeansWrapper.getDefaultInstance().wrap(bean); } public boolean isEmpty() { return false; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerPageContext1.java0000644000175000017500000000103211723544467027256 0ustar ebourgebourgpackage freemarker.ext.jsp; import freemarker.template.TemplateModelException; /** * @author Attila Szegedi * @version $Id: FreeMarkerPageContext1.java,v 1.1.2.1 2006/07/08 14:45:34 ddekany Exp $ */ class FreeMarkerPageContext1 extends FreeMarkerPageContext { private FreeMarkerPageContext1() throws TemplateModelException { super(); } static FreeMarkerPageContext create() throws TemplateModelException { return new FreeMarkerPageContext1(); } public void include (String s, boolean b) {} } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/PageContextFactory.java0000644000175000017500000000477411723544471026574 0ustar ebourgebourgpackage freemarker.ext.jsp; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.jsp.PageContext; import freemarker.core.Environment; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: PageContextFactory.java,v 1.2 2005/06/11 21:21:09 szegedia Exp $ */ class PageContextFactory { private static final Method constructor; static { Class impl; try { try { PageContext.class.getMethod("getELContext", (Class[]) null); impl = Class.forName("freemarker.ext.jsp.FreeMarkerPageContext21"); } catch(NoSuchMethodException e1) { try { PageContext.class.getMethod("getExpressionEvaluator", (Class[]) null); impl = Class.forName("freemarker.ext.jsp.FreeMarkerPageContext2"); } catch(NoSuchMethodException e2) { impl = Class.forName("freemarker.ext.jsp.FreeMarkerPageContext1"); } } constructor = impl.getDeclaredMethod("create", (Class[]) null); } catch(ClassNotFoundException e) { throw new NoClassDefFoundError(e.getMessage()); } catch(NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } static FreeMarkerPageContext getCurrentPageContext() throws TemplateModelException { Environment env = Environment.getCurrentEnvironment(); TemplateModel pageContextModel = env.getGlobalVariable(PageContext.PAGECONTEXT); if(pageContextModel instanceof FreeMarkerPageContext) { return (FreeMarkerPageContext)pageContextModel; } try { FreeMarkerPageContext pageContext = (FreeMarkerPageContext)constructor.invoke(null, (Object[]) null); env.setGlobalVariable(PageContext.PAGECONTEXT, pageContext); return pageContext; } catch(IllegalAccessException e) { throw new IllegalAccessError(e.getMessage()); } catch(InvocationTargetException e) { if(e.getTargetException() instanceof TemplateModelException) { throw (TemplateModelException)e.getTargetException(); } throw new UndeclaredThrowableException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerPageContext2.java0000644000175000017500000000541211723544470027257 0ustar ebourgebourgpackage freemarker.ext.jsp; import freemarker.log.Logger; import freemarker.template.TemplateModelException; import javax.servlet.jsp.el.ExpressionEvaluator; import javax.servlet.jsp.el.VariableResolver; import javax.servlet.jsp.el.ELException; import javax.servlet.jsp.JspFactory; import javax.servlet.jsp.PageContext; import javax.servlet.ServletException; import java.io.IOException; /** * Implementation of PageContext that contains JSP 2.0 specific methods. * * @author Attila Szegedi * @version $Id: FreeMarkerPageContext2.java,v 1.1.2.1 2006/07/08 14:45:34 ddekany Exp $ */ class FreeMarkerPageContext2 extends FreeMarkerPageContext { private static final Logger logger = Logger.getLogger("freemarker.jsp"); static { if(JspFactory.getDefaultFactory() == null) { JspFactory.setDefaultFactory(new FreeMarkerJspFactory2()); } logger.debug("Using JspFactory implementation class " + JspFactory.getDefaultFactory().getClass().getName()); } private FreeMarkerPageContext2() throws TemplateModelException { super(); } static FreeMarkerPageContext create() throws TemplateModelException { return new FreeMarkerPageContext2(); } /** * Attempts to locate and manufacture an expression evaulator instance. For this * to work you must have the Apache Commons-EL package in the classpath. If * Commons-EL is not available, this method will throw an UnsupportedOperationException. */ public ExpressionEvaluator getExpressionEvaluator() { try { Class type = Thread.currentThread().getContextClassLoader().loadClass ("org.apache.commons.el.ExpressionEvaluatorImpl"); return (ExpressionEvaluator) type.newInstance(); } catch (Exception e) { throw new UnsupportedOperationException("In order for the getExpressionEvaluator() " + "method to work, you must have downloaded the apache commons-el jar and " + "made it available in the classpath."); } } /** * Returns a variable resolver that will resolve variables by searching through * the page scope, request scope, session scope and application scope for an * attribute with a matching name. */ public VariableResolver getVariableResolver() { final PageContext ctx = this; return new VariableResolver() { public Object resolveVariable(String name) throws ELException { return ctx.findAttribute(name); } }; } /** * Includes the specified path. The flush argument is ignored! */ public void include(String path, boolean flush) throws IOException, ServletException { super.include(path); } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerJspFactory21.java0000644000175000017500000000177311723544470027211 0ustar ebourgebourgpackage freemarker.ext.jsp; import javax.servlet.ServletContext; import javax.servlet.jsp.JspApplicationContext; /** * @author Attila Szegedi * @version $Id: $ */ class FreeMarkerJspFactory21 extends FreeMarkerJspFactory { private static final String JSPCTX_KEY = FreeMarkerJspFactory21.class.getName() + "#jspAppContext"; protected String getSpecificationVersion() { return "2.1"; } public JspApplicationContext getJspApplicationContext(ServletContext ctx) { JspApplicationContext jspctx = (JspApplicationContext)ctx.getAttribute( JSPCTX_KEY); if(jspctx == null) { synchronized(ctx) { jspctx = (JspApplicationContext)ctx.getAttribute(JSPCTX_KEY); if(jspctx == null) { jspctx = new FreeMarkerJspApplicationContext(); ctx.setAttribute(JSPCTX_KEY, jspctx); } } } return jspctx; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/TagTransformModel.java0000644000175000017500000003534511723544471026411 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jsp; import java.beans.IntrospectionException; import java.io.CharArrayReader; import java.io.CharArrayWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Map; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTag; import javax.servlet.jsp.tagext.IterationTag; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TryCatchFinally; import freemarker.log.Logger; import freemarker.template.TemplateModelException; import freemarker.template.TemplateTransformModel; import freemarker.template.TransformControl; /** * @version $Id: TagTransformModel.java,v 1.17.2.2 2006/07/08 14:45:34 ddekany Exp $ * @author Attila Szegedi */ class TagTransformModel extends JspTagModelBase implements TemplateTransformModel { private static final Logger logger = Logger.getLogger("freemarker.jsp"); private final boolean isBodyTag; private final boolean isIterationTag; private final boolean isTryCatchFinally; public TagTransformModel(Class tagClass) throws IntrospectionException { super(tagClass); isIterationTag = IterationTag.class.isAssignableFrom(tagClass); isBodyTag = isIterationTag && BodyTag.class.isAssignableFrom(tagClass); isTryCatchFinally = TryCatchFinally.class.isAssignableFrom(tagClass); } public Writer getWriter(Writer out, Map args) throws TemplateModelException { try { Tag tag = (Tag)getTagInstance(); FreeMarkerPageContext pageContext = PageContextFactory.getCurrentPageContext(); Tag parentTag = (Tag)pageContext.peekTopTag(Tag.class); tag.setParent(parentTag); tag.setPageContext(pageContext); setupTag(tag, args, pageContext.getObjectWrapper()); // If the parent of this writer is not a JspWriter itself, use // a little Writer-to-JspWriter adapter... boolean usesAdapter; if(out instanceof JspWriter) { // This is just a sanity check. If it were JDK 1.4-only, // we'd use an assert. if(out != pageContext.getOut()) { throw new TemplateModelException( "out != pageContext.getOut(). Out is " + out + " pageContext.getOut() is " + pageContext.getOut()); } usesAdapter = false; } else { out = new JspWriterAdapter(out); pageContext.pushWriter((JspWriter)out); usesAdapter = true; } JspWriter w = new TagWriter(out, tag, pageContext, usesAdapter); pageContext.pushTopTag(tag); pageContext.pushWriter(w); return w; } catch(TemplateModelException e) { throw e; } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new TemplateModelException(e); } } /** * An implementation of BodyContent that buffers it's input to a char[]. */ static class BodyContentImpl extends BodyContent { private CharArrayWriter buf; BodyContentImpl(JspWriter out, boolean buffer) { super(out); if (buffer) initBuffer(); } void initBuffer() { buf = new CharArrayWriter(); } public void flush() throws IOException { if(buf == null) { getEnclosingWriter().flush(); } } public void clear() throws IOException { if(buf != null) { buf = new CharArrayWriter(); } else { throw new IOException("Can't clear"); } } public void clearBuffer() throws IOException { if(buf != null) { buf = new CharArrayWriter(); } else { throw new IOException("Can't clear"); } } public int getRemaining() { return Integer.MAX_VALUE; } public void newLine() throws IOException { write(JspWriterAdapter.NEWLINE); } public void close() throws IOException { } public void print(boolean arg0) throws IOException { write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString()); } public void print(char arg0) throws IOException { write(arg0); } public void print(char[] arg0) throws IOException { write(arg0); } public void print(double arg0) throws IOException { write(Double.toString(arg0)); } public void print(float arg0) throws IOException { write(Float.toString(arg0)); } public void print(int arg0) throws IOException { write(Integer.toString(arg0)); } public void print(long arg0) throws IOException { write(Long.toString(arg0)); } public void print(Object arg0) throws IOException { write(arg0 == null ? "null" : arg0.toString()); } public void print(String arg0) throws IOException { write(arg0); } public void println() throws IOException { newLine(); } public void println(boolean arg0) throws IOException { print(arg0); newLine(); } public void println(char arg0) throws IOException { print(arg0); newLine(); } public void println(char[] arg0) throws IOException { print(arg0); newLine(); } public void println(double arg0) throws IOException { print(arg0); newLine(); } public void println(float arg0) throws IOException { print(arg0); newLine(); } public void println(int arg0) throws IOException { print(arg0); newLine(); } public void println(long arg0) throws IOException { print(arg0); newLine(); } public void println(Object arg0) throws IOException { print(arg0); newLine(); } public void println(String arg0) throws IOException { print(arg0); newLine(); } public void write(int c) throws IOException { if(buf != null) { buf.write(c); } else { getEnclosingWriter().write(c); } } public void write(char[] cbuf, int off, int len) throws IOException { if(buf != null) { buf.write(cbuf, off, len); } else { getEnclosingWriter().write(cbuf, off, len); } } public String getString() { return buf.toString(); } public Reader getReader() { return new CharArrayReader(buf.toCharArray()); } public void writeOut(Writer out) throws IOException { buf.writeTo(out); } } class TagWriter extends BodyContentImpl implements TransformControl { private final Tag tag; private final FreeMarkerPageContext pageContext; private boolean needPop = true; private final boolean needDoublePop; TagWriter(Writer out, Tag tag, FreeMarkerPageContext pageContext, boolean needDoublePop) { super((JspWriter)out, false); this.needDoublePop = needDoublePop; this.tag = tag; this.pageContext = pageContext; } public String toString() { return "TagWriter for " + tag.getClass().getName() + " wrapping a " + getEnclosingWriter().toString(); } Tag getTag() { return tag; } FreeMarkerPageContext getPageContext() { return pageContext; } public int onStart() throws TemplateModelException { try { int dst = tag.doStartTag(); switch(dst) { case Tag.SKIP_BODY: // EVAL_PAGE is illegal actually, but some taglibs out there // use it, and it seems most JSP compilers allow them to and // treat it identically to SKIP_BODY, so we're going with // the flow and we allow it too, altough strictly speaking // it is in violation of the spec. case Tag.EVAL_PAGE: { endEvaluation(); return TransformControl.SKIP_BODY; } case BodyTag.EVAL_BODY_BUFFERED: { if(isBodyTag) { initBuffer(); BodyTag btag = (BodyTag)tag; btag.setBodyContent(this); btag.doInitBody(); } else { throw new TemplateModelException("Can't buffer body since " + tag.getClass().getName() + " does not implement BodyTag."); } // Intentional fall-through } case Tag.EVAL_BODY_INCLUDE: { return TransformControl.EVALUATE_BODY; } default: { throw new RuntimeException("Illegal return value " + dst + " from " + tag.getClass().getName() + ".doStartTag()"); } } } catch(JspException e) { throw new TemplateModelException(e.getMessage(), e); } } public int afterBody() throws TemplateModelException { try { if(isIterationTag) { int dab = ((IterationTag)tag).doAfterBody(); switch(dab) { case Tag.SKIP_BODY: { endEvaluation(); return END_EVALUATION; } case IterationTag.EVAL_BODY_AGAIN: { return REPEAT_EVALUATION; } default: { throw new TemplateModelException("Unexpected return value " + dab + "from " + tag.getClass().getName() + ".doAfterBody()"); } } } endEvaluation(); return END_EVALUATION; } catch(JspException e) { throw new TemplateModelException(e); } } private void endEvaluation() throws JspException { if(needPop) { pageContext.popWriter(); needPop = false; } if(tag.doEndTag() == Tag.SKIP_PAGE) { logger.warn("Tag.SKIP_PAGE was ignored from a " + tag.getClass().getName() + " tag."); } } public void onError(Throwable t) throws Throwable { if(isTryCatchFinally) { ((TryCatchFinally)tag).doCatch(t); } else { throw t; } } public void close() { if(needPop) { pageContext.popWriter(); } pageContext.popTopTag(); try { if(isTryCatchFinally) { ((TryCatchFinally)tag).doFinally(); } // No pooling yet tag.release(); } finally { if(needDoublePop) { pageContext.popWriter(); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/EventForwarding.java0000644000175000017500000002240611723544472026120 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.ext.jsp; import java.util.ArrayList; import java.util.EventListener; import java.util.Iterator; import java.util.List; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; import freemarker.log.Logger; /** * An instance of this class should be registered as a <listener> in * the web.xml descriptor in order to correctly dispatch events to * event listeners that are specified in TLD files. * @author Attila Szegedi * @version $Id: EventForwarding.java,v 1.5 2003/01/24 10:19:33 szegedia Exp $ */ public class EventForwarding implements ServletContextAttributeListener, ServletContextListener, HttpSessionListener, HttpSessionAttributeListener { private static final Logger logger = Logger.getLogger("freemarker.jsp"); private static final String ATTR_NAME = EventForwarding.class.getName(); private final List servletContextAttributeListeners = new ArrayList(); private final List servletContextListeners = new ArrayList(); private final List httpSessionAttributeListeners = new ArrayList(); private final List httpSessionListeners = new ArrayList(); void addListeners(List listeners) { for (Iterator iter = listeners.iterator(); iter.hasNext();) { addListener((EventListener)iter.next()); } } private void addListener(EventListener listener) { boolean added = false; if(listener instanceof ServletContextAttributeListener) { addListener(servletContextAttributeListeners, listener); added = true; } if(listener instanceof ServletContextListener) { addListener(servletContextListeners, listener); added = true; } if(listener instanceof HttpSessionAttributeListener) { addListener(httpSessionAttributeListeners, listener); added = true; } if(listener instanceof HttpSessionListener) { addListener(httpSessionListeners, listener); added = true; } if(!added) { logger.warn( "Listener of class " + listener.getClass().getName() + "wasn't registered as it doesn't implement any of the " + "recognized listener interfaces."); } } static EventForwarding getInstance(ServletContext context) { return (EventForwarding)context.getAttribute(ATTR_NAME); } private void addListener(List listeners, EventListener listener) { synchronized(listeners) { listeners.add(listener); } } public void attributeAdded(ServletContextAttributeEvent arg0) { synchronized(servletContextAttributeListeners) { int s = servletContextAttributeListeners.size(); for(int i = 0; i < s; ++i) { ((ServletContextAttributeListener)servletContextAttributeListeners.get(i)).attributeAdded(arg0); } } } public void attributeRemoved(ServletContextAttributeEvent arg0) { synchronized(servletContextAttributeListeners) { int s = servletContextAttributeListeners.size(); for(int i = 0; i < s; ++i) { ((ServletContextAttributeListener)servletContextAttributeListeners.get(i)).attributeRemoved(arg0); } } } public void attributeReplaced(ServletContextAttributeEvent arg0) { synchronized(servletContextAttributeListeners) { int s = servletContextAttributeListeners.size(); for(int i = 0; i < s; ++i) { ((ServletContextAttributeListener)servletContextAttributeListeners.get(i)).attributeReplaced(arg0); } } } public void contextInitialized(ServletContextEvent arg0) { arg0.getServletContext().setAttribute(ATTR_NAME, this); synchronized(servletContextListeners) { int s = servletContextListeners.size(); for(int i = 0; i < s; ++i) { ((ServletContextListener)servletContextListeners.get(i)).contextInitialized(arg0); } } } public void contextDestroyed(ServletContextEvent arg0) { synchronized(servletContextListeners) { int s = servletContextListeners.size(); for(int i = s - 1; i >= 0; --i) { ((ServletContextListener)servletContextListeners.get(i)).contextDestroyed(arg0); } } } public void sessionCreated(HttpSessionEvent arg0) { synchronized(httpSessionListeners) { int s = httpSessionListeners.size(); for(int i = 0; i < s; ++i) { ((HttpSessionListener)httpSessionListeners.get(i)).sessionCreated(arg0); } } } public void sessionDestroyed(HttpSessionEvent arg0) { synchronized(httpSessionListeners) { int s = httpSessionListeners.size(); for(int i = s - 1; i >= 0; --i) { ((HttpSessionListener)httpSessionListeners.get(i)).sessionDestroyed(arg0); } } } public void attributeAdded(HttpSessionBindingEvent arg0) { synchronized(httpSessionAttributeListeners) { int s = httpSessionAttributeListeners.size(); for(int i = 0; i < s; ++i) { ((HttpSessionAttributeListener)httpSessionAttributeListeners.get(i)).attributeAdded(arg0); } } } public void attributeRemoved(HttpSessionBindingEvent arg0) { synchronized(httpSessionAttributeListeners) { int s = httpSessionAttributeListeners.size(); for(int i = 0; i < s; ++i) { ((HttpSessionAttributeListener)httpSessionAttributeListeners.get(i)).attributeRemoved(arg0); } } } public void attributeReplaced(HttpSessionBindingEvent arg0) { synchronized(httpSessionAttributeListeners) { int s = httpSessionAttributeListeners.size(); for(int i = 0; i < s; ++i) { ((HttpSessionAttributeListener)httpSessionAttributeListeners.get(i)).attributeReplaced(arg0); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerJspFactory2.java0000644000175000017500000000035011723544471027117 0ustar ebourgebourgpackage freemarker.ext.jsp; /** * @author Attila Szegedi * @version $Id: $ */ class FreeMarkerJspFactory2 extends FreeMarkerJspFactory { protected String getSpecificationVersion() { return "2.0"; } }libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/FreeMarkerPageContext21.java0000644000175000017500000000740311723544471027343 0ustar ebourgebourgpackage freemarker.ext.jsp; import java.security.AccessController; import java.security.PrivilegedAction; import javax.el.ELContext; import javax.servlet.jsp.JspApplicationContext; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspFactory; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.el.ELException; import javax.servlet.jsp.el.ExpressionEvaluator; import javax.servlet.jsp.el.VariableResolver; import freemarker.log.Logger; import freemarker.template.TemplateModelException; /** * Implementation of PageContext that contains JSP 2.0 and JSP 2.1 specific methods. * * @author Attila Szegedi * @version $Id: FreeMarkerPageContext2.java,v 1.1 2005/06/11 12:13:39 szegedia Exp $ */ class FreeMarkerPageContext21 extends FreeMarkerPageContext { private static final Logger logger = Logger.getLogger("freemarker.jsp"); static { if(JspFactory.getDefaultFactory() == null) { JspFactory.setDefaultFactory(new FreeMarkerJspFactory21()); } logger.debug("Using JspFactory implementation class " + JspFactory.getDefaultFactory().getClass().getName()); } private FreeMarkerPageContext21() throws TemplateModelException { super(); } static FreeMarkerPageContext create() throws TemplateModelException { return new FreeMarkerPageContext21(); } /** * Attempts to locate and manufacture an expression evaulator instance. For this * to work you must have the Apache Commons-EL package in the classpath. If * Commons-EL is not available, this method will throw an UnsupportedOperationException. */ public ExpressionEvaluator getExpressionEvaluator() { try { Class type = ((ClassLoader)AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return Thread.currentThread().getContextClassLoader(); } })).loadClass ("org.apache.commons.el.ExpressionEvaluatorImpl"); return (ExpressionEvaluator) type.newInstance(); } catch (Exception e) { throw new UnsupportedOperationException("In order for the getExpressionEvaluator() " + "method to work, you must have downloaded the apache commons-el jar and " + "made it available in the classpath."); } } /** * Returns a variable resolver that will resolve variables by searching through * the page scope, request scope, session scope and application scope for an * attribute with a matching name. */ public VariableResolver getVariableResolver() { final PageContext ctx = this; return new VariableResolver() { public Object resolveVariable(String name) throws ELException { return ctx.findAttribute(name); } }; } private ELContext elContext; public ELContext getELContext() { if(elContext == null) { JspApplicationContext jspctx = JspFactory.getDefaultFactory().getJspApplicationContext(getServletContext()); if(jspctx instanceof FreeMarkerJspApplicationContext) { elContext = ((FreeMarkerJspApplicationContext)jspctx).createNewELContext(this); elContext.putContext(JspContext.class, this); } else { throw new UnsupportedOperationException( "Can not create an ELContext using a foreign JspApplicationContext\n" + "Consider dropping a private instance of JSP 2.1 API JAR file in\n" + "your WEB-INF/lib directory and then try again."); } } return elContext; } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/JspTagModelBase.java0000644000175000017500000000666211723544470025764 0ustar ebourgebourgpackage freemarker.ext.jsp; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import freemarker.ext.beans.BeansWrapper; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.utility.StringUtil; class JspTagModelBase { private final Class tagClass; private final Method dynaSetter; private final Map propertySetters = new HashMap(); protected JspTagModelBase(Class tagClass) throws IntrospectionException { this.tagClass = tagClass; BeanInfo bi = Introspector.getBeanInfo(tagClass); PropertyDescriptor[] pda = bi.getPropertyDescriptors(); for (int i = 0; i < pda.length; i++) { PropertyDescriptor pd = pda[i]; Method m = pd.getWriteMethod(); if(m != null) { propertySetters.put(pd.getName(), m); } } // Check to see if the tag implements the JSP2.0 DynamicAttributes // interface, to allow setting of arbitrary attributes Method dynaSetter; try { dynaSetter = tagClass.getMethod("setDynamicAttribute", new Class[] {String.class, String.class, Object.class}); } catch (NoSuchMethodException nsme) { dynaSetter = null; } this.dynaSetter = dynaSetter; } Object getTagInstance() throws IllegalAccessException, InstantiationException { return tagClass.newInstance(); } void setupTag(Object tag, Map args, ObjectWrapper wrapper) throws TemplateModelException, InvocationTargetException, IllegalAccessException { BeansWrapper bwrapper = wrapper instanceof BeansWrapper ? (BeansWrapper)wrapper : BeansWrapper.getDefaultInstance(); if(args != null && !args.isEmpty()) { Object[] aarg = new Object[1]; for (Iterator iter = args.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); Object arg = bwrapper.unwrap((TemplateModel)entry.getValue()); aarg[0] = arg; Method m = (Method)propertySetters.get(entry.getKey()); if (m == null) { if (dynaSetter == null) { throw new TemplateModelException("Unknown property " + StringUtil.jQuote(entry.getKey().toString()) + " on instance of " + tagClass.getName()); } else { dynaSetter.invoke(tag, new Object[] {null, entry.getKey(), aarg[0]}); } } else { if(arg instanceof BigDecimal) { aarg[0] = BeansWrapper.coerceBigDecimal( (BigDecimal)arg, m.getParameterTypes()[0]); } m.invoke(tag, aarg); } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/package.html0000644000175000017500000000044411723544471024427 0ustar ebourgebourg

Classes for two-way FreeMarker-JSP integration. It contains both a JSP custom tag that allows embedding of FreeMarker templates inside JSP pages, as well as the infrastructure that allows JSP custom tags to be used inside FreeMarker templates. libfreemarker-java-2.3.19.orig/src/freemarker/ext/jsp/SimpleTagDirectiveModel.java0000644000175000017500000000653011723544471027520 0ustar ebourgebourgpackage freemarker.ext.jsp; import java.beans.IntrospectionException; import java.io.IOException; import java.io.Writer; import java.util.Map; import javax.servlet.jsp.JspContext; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.JspTag; import javax.servlet.jsp.tagext.SimpleTag; import javax.servlet.jsp.tagext.Tag; import freemarker.core.Environment; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * @author Attila Szegedi * @version $Id: $ */ class SimpleTagDirectiveModel extends JspTagModelBase implements TemplateDirectiveModel { protected SimpleTagDirectiveModel(Class tagClass) throws IntrospectionException { super(tagClass); if(!SimpleTag.class.isAssignableFrom(tagClass)) { throw new IllegalArgumentException(tagClass.getName() + " does not implement either the " + Tag.class.getName() + " interface or the " + SimpleTag.class.getName() + " interface."); } } public void execute(Environment env, Map args, TemplateModel[] outArgs, final TemplateDirectiveBody body) throws TemplateException, IOException { try { SimpleTag tag = (SimpleTag)getTagInstance(); final FreeMarkerPageContext pageContext = PageContextFactory.getCurrentPageContext(); pageContext.pushWriter(new JspWriterAdapter(env.getOut())); try { tag.setJspContext(pageContext); JspTag parentTag = (JspTag)pageContext.peekTopTag(JspTag.class); if(parentTag != null) { tag.setParent(parentTag); } setupTag(tag, args, pageContext.getObjectWrapper()); if(body != null) { tag.setJspBody(new JspFragment() { public JspContext getJspContext() { return pageContext; } public void invoke(Writer out) throws JspException, IOException { try { body.render(out == null ? pageContext.getOut() : out); } catch(TemplateException e) { throw new JspException(e); } } }); pageContext.pushTopTag(tag); try { tag.doTag(); } finally { pageContext.popTopTag(); } } else { tag.doTag(); } } finally { pageContext.popWriter(); } } catch(TemplateException e) { throw e; } catch(RuntimeException e) { throw e; } catch(Exception e) { throw new TemplateModelException(e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/0000755000175000017500000000000012164627123022357 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateTransformModel.java0000644000175000017500000001271111723544470027657 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.template.utility.DeepUnwrap; /** * Objects that implement this interface can be used as user-defined directives * (much like macros); you should rather use the newer {@link TemplateDirectiveModel} * instead. Altough implementing output filters is more handy with this interface, * this interface will be certainly deprecated as superfluous, starting from * FreeMarker 2.4. But as far as the template engine is concerned, you can use both * equivalently as a user-defined directive. * *

Note that, as of FreeMarker 2.1, TemplateTransformModel * has changed. This is a more powerful implementation. * There is a quick-and-dirty way to patch any legacy * TemplateTransformModel so that it implements the new API. * You simply add the following as your implementation * of the getWriter() call: *

 * 
 *    public Writer getWriter(final Writer out, 
 *                            Map args) 
 *    {
 *       final StringBuffer buf = new StringBuffer();
 *       return new Writer() {
 *           public void write(char cbuf[], int off, int len) {
 *               buf.append(cbuf, off, len);
 *           }
 *
 *           public void flush() throws IOException {
 *               out.flush();
 *           }
 * 
 *           public void close() throws IOException {
 *               StringReader sr = new StringReader(buf.toString());
 *               StringWriter sw = new StringWriter();
 *               transform(sr, sw);
 *               out.write(sw.toString());
 *           }
 *       };
 *   }
 *
 * 
 * 
* * @author Attila Szegedi * @version $Id: TemplateTransformModel.java,v 1.36 2003/04/11 20:57:32 revusky Exp $ */ public interface TemplateTransformModel extends TemplateModel { /** * Returns a writer that will be used by the engine to feed the * transformation input to the transform. Each call to this method * must return a new instance of the writer so that the transformation * is thread-safe. * @param out the character stream to which to write the transformed output * @param args the arguments (if any) passed to the transformation as a * map of key/value pairs where the keys are strings and the arguments are * TemplateModel instances. This is never null. If you need to convert the * template models to POJOs, you can use the utility methods in the * {@link DeepUnwrap} class. * @return a writer to which the engine will feed the transformation * input, or null if the transform does not support nested content (body). * The returned writer can implement the {@link TransformControl} * interface if it needs advanced control over the evaluation of the * transformation body. */ Writer getWriter(Writer out, Map args) throws TemplateModelException, IOException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateHashModelEx.java0000644000175000017500000001053111723544470027062 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** *

An extended hash interface with a couple of extra hooks. If a class * implements this interface, then the built-in operators ?size, * ?keys, and ?values can be applied to its * instances in the template.

* *

As of version 2.2.2, the engine will automatically wrap the * collections returned by keys and values to * present them as sequences to the template. For performance, you may * wish to return objects that implement both TemplateCollectionModel * and {@link TemplateSequenceModel}. Note that the wrapping to sequence happens * on demand; if the template does not try to use the variable returned by * ?keys or ?values as sequence (theKeys?size, or theKeys[x], * or theKeys?sort, etc.), just iterates over the variable * (<#list foo?keys as k>...), then no wrapping to * sequence will happen, thus there will be no overhead. * * @author Jonathan Revusky * @see SimpleHash * @version $Id: TemplateHashModelEx.java,v 1.13 2003/06/08 00:58:15 herbyderby Exp $ */ public interface TemplateHashModelEx extends TemplateHashModel { /** * @return the number of key/value mappings in the hash. */ int size() throws TemplateModelException; /** * @return a collection containing the keys in the hash. Every element of * the returned collection must implement the {@link TemplateScalarModel} * (as the keys of hashes are always strings). */ TemplateCollectionModel keys() throws TemplateModelException; /** * @return a collection containing the values in the hash. */ TemplateCollectionModel values() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateExceptionHandler.java0000644000175000017500000001560611723544471030166 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.Writer; import java.io.PrintWriter; import freemarker.core.Environment; /** * An API for objects that handle exceptions that are thrown during * template rendering. * @author Jonathan Revusky */ public interface TemplateExceptionHandler { /** * handle the exception. * @param te the exception that occurred. * @param env The environment object that represents the rendering context * @param out the character output stream to output to. */ void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException; /** * This is a TemplateExceptionHandler which simply skips errors. It does nothing * to handle the event. Note that the exception is still logged in any case, before * being passed to the handler. */ TemplateExceptionHandler IGNORE_HANDLER = new TemplateExceptionHandler() { public void handleTemplateException(TemplateException te, Environment env, Writer out) { } }; /** * This is a TemplateExceptionHandler that simply rethrows the exception. * Note that the exception is logged before being rethrown. */ TemplateExceptionHandler RETHROW_HANDLER =new TemplateExceptionHandler() { public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException { throw te; } }; /** * This is a TemplateExceptionHandler used when you develop the templates. This handler * outputs the stack trace information to the client and then rethrows the exception. */ TemplateExceptionHandler DEBUG_HANDLER =new TemplateExceptionHandler() { public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException { PrintWriter pw = (out instanceof PrintWriter) ? (PrintWriter) out : new PrintWriter(out); te.printStackTrace(pw); pw.flush(); throw te; } }; /** * This is a TemplateExceptionHandler used when you develop HTML templates. This handler * outputs the stack trace information to the client and then rethrows the exception, and * surrounds it with tags to make the error message readable with the browser. */ TemplateExceptionHandler HTML_DEBUG_HANDLER =new TemplateExceptionHandler() { public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException { PrintWriter pw = (out instanceof PrintWriter) ? (PrintWriter) out : new PrintWriter(out); pw.println("" + "" + "" + "" + "" + "" + "" + "" + "

" + "FreeMarker template error!" + "
");
                    te.printStackTrace(pw);
                    pw.println("
"); pw.flush(); throw te; } }; } libfreemarker-java-2.3.19.orig/src/freemarker/template/ObjectWrapper.java0000644000175000017500000001000011723544471025764 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import freemarker.ext.beans.BeansWrapper; /** *

An object that knows how to "wrap" a java object * as a TemplateModel instance. * * @version $Id: ObjectWrapper.java,v 1.15 2003/06/22 17:50:28 ddekany Exp $ */ public interface ObjectWrapper { /** * An ObjectWrapper that works similarly to {@link #SIMPLE_WRAPPER}, but * exposes the objects methods and JavaBeans properties as hash elements * and custom handling for Java Maps, ResourceBundles, etc. */ ObjectWrapper BEANS_WRAPPER = BeansWrapper.getDefaultInstance(); /** * The default object wrapper implementation. * Wraps Maps as SimpleHash and Lists as SimpleSequences, Strings and * Numbers as SimpleScalar and SimpleNumber respectively. * Other objects are beans-wrapped, thus exposing reflection-based information. */ ObjectWrapper DEFAULT_WRAPPER = DefaultObjectWrapper.instance; /** * Object wrapper that uses SimpleXXX wrappers only. * This wrapper has far more restrictive semantics. It * behaves like the DEFAULT_WRAPPER, but for objects * that it does not know how to wrap as a SimpleXXX, it * throws an exception. It makes no use of reflection-based * exposure of methods. */ ObjectWrapper SIMPLE_WRAPPER = SimpleObjectWrapper.instance; /** * @return a TemplateModel wrapper of the object passed in. */ TemplateModel wrap(Object obj) throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/0000755000175000017500000000000012164627123024062 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/template/utility/OptimizerUtil.java0000644000175000017500000001300311723544470027545 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * @version $Id: OptimizerUtil.java,v 1.9 2003/02/25 11:52:58 szegedia Exp $ * @author Attila Szegedi */ public class OptimizerUtil { private static final BigInteger INTEGER_MIN = new BigInteger(Integer.toString(Integer.MIN_VALUE)); private static final BigInteger INTEGER_MAX = new BigInteger(Integer.toString(Integer.MAX_VALUE)); private static final BigInteger LONG_MIN = new BigInteger(Long.toString(Long.MIN_VALUE)); private static final BigInteger LONG_MAX = new BigInteger(Long.toString(Long.MAX_VALUE)); private OptimizerUtil() { } public static List optimizeListStorage(List list) { switch(list.size()) { case 0: { return Collections.EMPTY_LIST; } case 1: { return Collections12.singletonList(list.get(0)); } default: { if(list instanceof ArrayList) { ((ArrayList)list).trimToSize(); } return list; } } } /** * This is needed to reverse the extreme conversions in arithmetic * operations so that numbers can be meaningfully used with models that * don't know what to do with a BigDecimal. Of course, this will make * impossible for these models (i.e. Jython) to receive a BigDecimal even if * it was originally placed as such in the data model. However, since * arithmetic operations aggressively erase the information regarding the * original number type, we have no other choice to ensure expected operation * in majority of cases. */ public static Number optimizeNumberRepresentation(Number number) { if(number instanceof BigDecimal) { BigDecimal bd = (BigDecimal) number; if(bd.scale() == 0) { // BigDecimal -> BigInteger number = bd.unscaledValue(); } else { double d = bd.doubleValue(); if(d != Double.POSITIVE_INFINITY && d != Double.NEGATIVE_INFINITY) { // BigDecimal -> Double return new Double(d); } } } if(number instanceof BigInteger) { BigInteger bi = (BigInteger)number; if(bi.compareTo(INTEGER_MAX) <= 0 && bi.compareTo(INTEGER_MIN) >= 0) { // BigInteger -> Integer return new Integer(bi.intValue()); } if(bi.compareTo(LONG_MAX) <= 0 && bi.compareTo(LONG_MIN) >= 0) { // BigInteger -> Long return new Long(bi.longValue()); } } return number; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/ObjectConstructor.java0000644000175000017500000000762711723544470030420 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.util.List; import freemarker.ext.beans.BeansWrapper; import freemarker.template.*; import freemarker.template.utility.ClassUtil; /** * An object that you can make available in a template * to instantiate arbitrary beans-wrapped objects in a template. * Beware of this class's security implications. It allows * the instantiation of arbitrary objects and invoking * methods on them. Usage is something like: *
*
myDataModel.put("objectConstructor", new ObjectConstructor()); *
*
And then from your FTL code: *
*
<#assign aList = objectConstructor("java.util.ArrayList", 100)> */ public class ObjectConstructor implements TemplateMethodModelEx { public Object exec(List args) throws TemplateModelException { if (args.isEmpty()) { throw new TemplateModelException("This method must have at least one argument, the name of the class to instantiate."); } String classname = args.get(0).toString(); Class cl = null; try { cl = ClassUtil.forName(classname); } catch (Exception e) { throw new TemplateModelException(e.getMessage()); } BeansWrapper bw = BeansWrapper.getDefaultInstance(); Object obj = bw.newInstance(cl, args.subList(1, args.size())); return bw.wrap(obj); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/JythonRuntime.java0000644000175000017500000001010111723544472027542 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.io.IOException; import java.io.Writer; import java.util.Map; import org.python.core.PyObject; import org.python.util.PythonInterpreter; import freemarker.template.TemplateTransformModel; import freemarker.core.Environment; /** * A crude first pass at an embeddable Jython interpreter * @author Jonathan Revusky */ public class JythonRuntime extends PythonInterpreter implements TemplateTransformModel { public Writer getWriter(final Writer out, final Map args) { final StringBuffer buf = new StringBuffer(); final Environment env = Environment.getCurrentEnvironment(); return new Writer() { public void write(char cbuf[], int off, int len) { buf.append(cbuf, off, len); } public void flush() throws IOException { interpretBuffer(); out.flush(); } public void close() { interpretBuffer(); } private void interpretBuffer() { synchronized(JythonRuntime.this) { PyObject prevOut = systemState.stdout; try { setOut(out); set("env", env); exec(buf.toString()); buf.setLength(0); } finally { setOut(prevOut); } } } }; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/XmlEscape.java0000644000175000017500000001242411723544470026614 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.template.TemplateTransformModel; /** * Performs an XML escaping of a given template fragment. Specifically, * < > " ' and & are all turned into entity references. * *

An instance of this tarnsform is initially visible as shared * variable called xml_escape.

* * @version $Id: XmlEscape.java,v 1.29 2004/11/27 14:49:57 ddekany Exp $ */ public class XmlEscape implements TemplateTransformModel { private static final char[] LT = "<".toCharArray(); private static final char[] GT = ">".toCharArray(); private static final char[] AMP = "&".toCharArray(); private static final char[] QUOT = """.toCharArray(); private static final char[] APOS = "'".toCharArray(); public Writer getWriter(final Writer out, Map args) { return new Writer() { public void write(int c) throws IOException { switch(c) { case '<': out.write(LT, 0, 4); break; case '>': out.write(GT, 0, 4); break; case '&': out.write(AMP, 0, 5); break; case '"': out.write(QUOT, 0, 6); break; case '\'': out.write(APOS, 0, 6); break; default: out.write(c); } } public void write(char cbuf[], int off, int len) throws IOException { int lastoff = off; int lastpos = off + len; for (int i = off; i < lastpos; i++) { switch (cbuf[i]) { case '<': out.write(cbuf, lastoff, i - lastoff); out.write(LT, 0, 4); lastoff = i + 1; break; case '>': out.write(cbuf, lastoff, i - lastoff); out.write(GT, 0, 4); lastoff = i + 1; break; case '&': out.write(cbuf, lastoff, i - lastoff); out.write(AMP, 0, 5); lastoff = i + 1; break; case '"': out.write(cbuf, lastoff, i - lastoff); out.write(QUOT, 0, 6); lastoff = i + 1; break; case '\'': out.write(cbuf, lastoff, i - lastoff); out.write(APOS, 0, 6); lastoff = i + 1; break; } } int remaining = lastpos - lastoff; if(remaining > 0) { out.write(cbuf, lastoff, remaining); } } public void flush() throws IOException { out.flush(); } public void close() { } }; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/HtmlEscape.java0000644000175000017500000001257711723544471026772 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.template.TemplateTransformModel; /** * Performs an HTML escape of a given template fragment. Specifically, * < > " and & are all turned into entities. * *

Usage:
* From java:

*
 * SimpleHash root = new SimpleHash();
 *
 * root.put( "htmlEscape", new freemarker.template.utility.HtmlEscape() );
 *
 * ...
 * 
* *

From your FreeMarker template:

*
 *
 * The following is HTML-escaped:
 * <transform htmlEscape>
 *   <p>This paragraph has all HTML special characters escaped.</p>
 * </transform>
 *
 * ...
 * 
* * @version $Id: HtmlEscape.java,v 1.29 2003/02/25 00:28:16 revusky Exp $ * @see freemarker.template.utility.XmlEscape */ public class HtmlEscape implements TemplateTransformModel { private static final char[] LT = "<".toCharArray(); private static final char[] GT = ">".toCharArray(); private static final char[] AMP = "&".toCharArray(); private static final char[] QUOT = """.toCharArray(); public Writer getWriter(final Writer out, Map args) { return new Writer() { public void write(int c) throws IOException { switch(c) { case '<': out.write(LT, 0, 4); break; case '>': out.write(GT, 0, 4); break; case '&': out.write(AMP, 0, 5); break; case '"': out.write(QUOT, 0, 6); break; default: out.write(c); } } public void write(char cbuf[], int off, int len) throws IOException { int lastoff = off; int lastpos = off + len; for (int i = off; i < lastpos; i++) { switch (cbuf[i]) { case '<': out.write(cbuf, lastoff, i - lastoff); out.write(LT, 0, 4); lastoff = i + 1; break; case '>': out.write(cbuf, lastoff, i - lastoff); out.write(GT, 0, 4); lastoff = i + 1; break; case '&': out.write(cbuf, lastoff, i - lastoff); out.write(AMP, 0, 5); lastoff = i + 1; break; case '"': out.write(cbuf, lastoff, i - lastoff); out.write(QUOT, 0, 6); lastoff = i + 1; break; } } int remaining = lastpos - lastoff; if(remaining > 0) { out.write(cbuf, lastoff, remaining); } } public void flush() throws IOException { out.flush(); } public void close() { } }; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/ToCanonical.java0000644000175000017500000001000611723544471027120 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import freemarker.template.*; import java.io.*; /** * Read in a template and convert it to a canonical format. */ public class ToCanonical { static Configuration config = Configuration.getDefaultConfiguration(); static public void main(String[] args) { config.setWhitespaceStripping(false); if (args.length == 0) { usage(); } for (int i=0; i"); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/Execute.java0000644000175000017500000001167111723544471026341 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import freemarker.template.*; import java.io.*; import java.util.*; /** *

Gives FreeMarker the the ability to execute external commands. Will fork * a process, and inline anything that process sends to stdout in the template. * Based on a patch submitted by Peter Molettiere.

* *

BE CAREFUL! this tag, depending on use, may allow you * to set something up so that users of your web * application could run arbitrary code on your server. * This can only happen if you allow unchecked GET/POST * submissions to be used as the command string in the * exec tag.

* *

Usage:
* From java:

*
 * SimpleHash root = new SimpleHash();
 *
 * root.put( "exec", new freemarker.template.utility.Execute() );
 *
 * ...
 * 
* *

From your FreeMarker template:

*
 *
 * The following is executed:
 * ${exec( "/usr/bin/ls" )}
 *
 * ...
 * 
* * @version $Id: Execute.java,v 1.14 2003/10/13 11:57:18 szegedia Exp $ */ public class Execute implements freemarker.template.TemplateMethodModel { private final static int OUTPUT_BUFFER_SIZE = 1024; /** * Executes a method call. * * @param arguments a List of String objects containing the values * of the arguments passed to the method. * @return the TemplateModel produced by the method, or null. */ public Object exec (List arguments) throws TemplateModelException { String aExecute; StringBuffer aOutputBuffer = new StringBuffer(); if( arguments.size() < 1 ) { throw new TemplateModelException( "Need an argument to execute" ); } aExecute = (String)(arguments.get(0)); try { Process exec = Runtime.getRuntime().exec( aExecute ); // stdout from the process comes in here InputStream execOut = exec.getInputStream(); Reader execReader = new InputStreamReader( execOut ); char[] buffer = new char[ OUTPUT_BUFFER_SIZE ]; int bytes_read = execReader.read( buffer ); while( bytes_read > 0 ) { aOutputBuffer.append( buffer, 0, bytes_read ); bytes_read = execReader.read( buffer ); } } catch( IOException ioe ) { throw new TemplateModelException( ioe.getMessage() ); } return aOutputBuffer.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/CaptureOutput.java0000644000175000017500000001672711723544470027571 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import freemarker.template.*; import freemarker.core.Environment; import java.io.*; import java.util.Map; /** * A transform that captures the output of a block of FTL code and stores that in a variable. * *

As this transform is initially present in the shared variable set, you can always * access it from the templates:

* *
 * <@capture_output var="captured">
 *   ...
 * </@capture_output>
 * 
* *

And later in the template you can use the captured output:

* * ${captured} * *

This transform requires one of three parameters: var, local, or global. * Each of them specifies the name of the variable that stores the captured output, but the first creates a * variable in a name-space (as <#assign>), the second creates a macro-local variable (as <#local>), * and the last creates a global variable (as <#global>). *

*

In the case of an assignment within a namespace, there is an optional parameter * namespace that indicates in which namespace to do the assignment. * if this is omitted, the current namespace is used, and this will be, by far, the most * common usage pattern.

* * @deprecated Use block-assignments instead, as <assign x>...</assign>. * * @version $Id: CaptureOutput.java,v 1.31 2004/01/06 17:06:43 szegedia Exp $ */ public class CaptureOutput implements TemplateTransformModel { public Writer getWriter(final Writer out, final Map args) throws TemplateModelException { String errmsg = "Must specify the name of the variable in " + "which to capture the output with the 'var' or 'local' or 'global' parameter."; if (args == null) throw new TemplateModelException(errmsg); boolean local = false, global=false; final TemplateModel nsModel = (TemplateModel) args.get("namespace"); Object varNameModel = args.get("var"); if (varNameModel == null) { varNameModel = args.get("local"); if (varNameModel == null) { varNameModel = args.get("global"); global = true; } else { local = true; } if (varNameModel == null) { throw new TemplateModelException(errmsg); } } if (args.size()==2) { if (nsModel == null) { throw new TemplateModelException("Second parameter can only be namespace"); } if (local) { throw new TemplateModelException("Cannot specify namespace for a local assignment"); } if (global) { throw new TemplateModelException("Cannot specify namespace for a global assignment"); } if (!(nsModel instanceof Environment.Namespace)) { throw new TemplateModelException("namespace parameter does not specify a namespace. It is a " + nsModel.getClass().getName()); } } else if (args.size() != 1) throw new TemplateModelException( "Bad parameters. Use only one of 'var' or 'local' or 'global' parameters."); if(!(varNameModel instanceof TemplateScalarModel)) { throw new TemplateModelException("'var' or 'local' or 'global' parameter doesn't evaluate to a string"); } final String varName = ((TemplateScalarModel) varNameModel).getAsString(); if(varName == null) { throw new TemplateModelException("'var' or 'local' or 'global' parameter evaluates to null string"); } final StringBuffer buf = new StringBuffer(); final Environment env = Environment.getCurrentEnvironment(); final boolean localVar = local; final boolean globalVar = global; return new Writer() { public void write(char cbuf[], int off, int len) { buf.append(cbuf, off, len); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { SimpleScalar result = new SimpleScalar(buf.toString()); try { if (localVar) { env.setLocalVariable(varName, result); } else if (globalVar) { env.setGlobalVariable(varName, result); } else { if (nsModel == null) { env.setVariable(varName, result); } else { ((Environment.Namespace) nsModel).put(varName, result); } } } catch (java.lang.IllegalStateException ise) { // if somebody uses 'local' outside a macro throw new IOException("Could not set variable " + varName + ": " + ise.getMessage()); } } }; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/StandardCompress.java0000644000175000017500000002271111723544471030210 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateTransformModel; /** *

A filter that compresses each sequence of consecutive whitespace * to a single line break (if the sequence contains a line break) or a * single space. In addition, leading and trailing whitespace is * completely removed.

* *

Specify the transform parameter single_line = true * to always compress to a single space instead of a line break.

* *

The default buffer size can be overridden by specifying a * buffer_size transform parameter (in bytes).

* *

Note: The compress tag is implemented using this filter

* *

Usage:
* From java:

*
 * SimpleHash root = new SimpleHash();
 *
 * root.put( "standardCompress", new freemarker.template.utility.StandardCompress() );
 *
 * ...
 * 
* *

From your FreeMarker template:

*
 * <transform standardCompress>
 *   <p>This    paragraph will have
 *       extraneous
 *
 * whitespace removed.</p>
 * </transform>
 * 
* *

Output:

*
 * <p>This paragraph will have
 * extraneous
 * whitespace removed.</p>
 * 
* * @version $Id: StandardCompress.java,v 1.14 2004/01/06 17:06:43 szegedia Exp $ */ public class StandardCompress implements TemplateTransformModel { private static final String BUFFER_SIZE_KEY = "buffer_size"; private static final String SINGLE_LINE_KEY = "single_line"; private int defaultBufferSize; public static final StandardCompress INSTANCE = new StandardCompress(); public StandardCompress() { this(2048); } /** * @param defaultBufferSize the default amount of characters to buffer */ public StandardCompress(int defaultBufferSize) { this.defaultBufferSize = defaultBufferSize; } public Writer getWriter(final Writer out, Map args) throws TemplateModelException { int bufferSize = defaultBufferSize; boolean singleLine = false; if (args != null) { try { TemplateNumberModel num = (TemplateNumberModel)args.get(BUFFER_SIZE_KEY); if (num != null) bufferSize = num.getAsNumber().intValue(); } catch (ClassCastException e) { throw new TemplateModelException("Expecting numerical argument to " + BUFFER_SIZE_KEY); } try { TemplateBooleanModel flag = (TemplateBooleanModel)args.get(SINGLE_LINE_KEY); if (flag != null) singleLine = flag.getAsBoolean(); } catch (ClassCastException e) { throw new TemplateModelException("Expecting boolean argument to " + SINGLE_LINE_KEY); } } return new StandardCompressWriter(out, bufferSize, singleLine); } private static class StandardCompressWriter extends Writer { private static final int MAX_EOL_LENGTH = 2; // CRLF is two bytes private static final int AT_BEGINNING = 0; private static final int SINGLE_LINE = 1; private static final int INIT = 2; private static final int SAW_CR = 3; private static final int LINEBREAK_CR = 4; private static final int LINEBREAK_CRLF = 5; private static final int LINEBREAK_LF = 6; private final Writer out; private final char[] buf; private final boolean singleLine; private int pos = 0; private boolean inWhitespace = true; private int lineBreakState = AT_BEGINNING; public StandardCompressWriter(Writer out, int bufSize, boolean singleLine) { this.out = out; this.singleLine = singleLine; buf = new char[bufSize]; } public void write(char[] cbuf, int off, int len) throws IOException { for (;;) { // Need to reserve space for the EOL potentially left in the state machine int room = buf.length - pos - MAX_EOL_LENGTH; if (room >= len) { writeHelper(cbuf, off, len); break; } else if (room <= 0) { flushInternal(); } else { writeHelper(cbuf, off, room); flushInternal(); off += room; len -= room; } } } private void writeHelper(char[] cbuf, int off, int len) { for (int i = off, end = off + len; i < end; i++) { char c = cbuf[i]; if (Character.isWhitespace(c)) { inWhitespace = true; updateLineBreakState(c); } else if (inWhitespace) { inWhitespace = false; writeLineBreakOrSpace(); buf[pos++] = c; } else { buf[pos++] = c; } } } /* \r\n => CRLF \r[^\n] => CR \r$ => CR [^\r]\n => LF ^\n => LF */ private void updateLineBreakState(char c) { switch (lineBreakState) { case INIT: if (c == '\r') { lineBreakState = SAW_CR; } else if (c == '\n') { lineBreakState = LINEBREAK_LF; } break; case SAW_CR: if (c == '\n') { lineBreakState = LINEBREAK_CRLF; } else { lineBreakState = LINEBREAK_CR; } } } private void writeLineBreakOrSpace() { switch (lineBreakState) { case SAW_CR: // whitespace ended with CR, fall through case LINEBREAK_CR: buf[pos++] = '\r'; break; case LINEBREAK_CRLF: buf[pos++] = '\r'; // fall through case LINEBREAK_LF: buf[pos++] = '\n'; break; case AT_BEGINNING: // ignore leading whitespace break; case INIT: case SINGLE_LINE: buf[pos++] = ' '; } lineBreakState = (singleLine) ? SINGLE_LINE : INIT; } private void flushInternal() throws IOException { out.write(buf, 0, pos); pos = 0; } public void flush() throws IOException { flushInternal(); out.flush(); } public void close() throws IOException { flushInternal(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/SecurityUtilities.java0000644000175000017500000001125111723544472030435 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedAction; import freemarker.log.Logger; /** * @author Attila Szegedi * @version $Id: SecurityUtilities.java,v 1.2 2004/11/11 13:27:39 szegedia Exp $ */ public class SecurityUtilities { private static final Logger logger = Logger.getLogger("freemarker.security"); private SecurityUtilities() { } public static String getSystemProperty(final String key) { return (String) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return System.getProperty(key); } }); } public static String getSystemProperty(final String key, final String defValue) { try { return (String) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return System.getProperty(key, defValue); } }); } catch(AccessControlException e) { logger.warn("Insufficient permissions to read system property " + StringUtil.jQuoteNoXSS(key) + ", using default value " + StringUtil.jQuoteNoXSS(defValue)); return defValue; } } public static Integer getSystemProperty(final String key, final int defValue) { try { return (Integer) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return Integer.getInteger(key, defValue); } }); } catch(AccessControlException e) { logger.warn("Insufficient permissions to read system property " + StringUtil.jQuote(key) + ", using default value " + defValue); return new Integer(defValue); } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/DateUtil.java0000644000175000017500000003633211723544467026460 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; public class DateUtil { public static final int ACCURACY_HOURS = 4; public static final int ACCURACY_MINUTES = 5; public static final int ACCURACY_SECONDS = 6; public static final int ACCURACY_MILLISECONDS = 7; public static final TimeZone UTC = TimeZone.getTimeZone("UTC"); private final static TimeZoneOffsetCalculator TIME_ZONE_OFFSET_CALCULATOR = getTimeZoneOffsetCalculator(); private static TimeZoneOffsetCalculator getTimeZoneOffsetCalculator() { try { Class cl = Class.forName( "freemarker.template.utility.J2SE14TimeZoneOffsetCalculator"); return (TimeZoneOffsetCalculator) cl.newInstance(); } catch (final Throwable e) { return new TimeZoneOffsetCalculator() { public int getOffset(TimeZone tz, Date date) { throw new RuntimeException( "Failed to create TimeZoneOffsetCalculator. " + "Note that this feature requires at least " + "Java 1.4.\nCause exception: " + e); } }; } } private DateUtil() { // can't be instantiated } /** * Returns the time zone object for the name (or ID). This differs from * {@link TimeZone#getTimeZone(String)} in that the latest returns GMT * if it doesn't recognize the name, while this throws an * {@link UnrecognizedTimeZoneException}. * * @throws UnrecognizedTimeZoneException */ public static TimeZone getTimeZone(String name) throws UnrecognizedTimeZoneException { if (isGMTish(name)) { if (name.equalsIgnoreCase("UTC")) { return UTC; } return TimeZone.getTimeZone(name); } TimeZone tz = TimeZone.getTimeZone(name); if (isGMTish(tz.getID())) { throw new UnrecognizedTimeZoneException(name); } return tz; } /** * Tells if a offset or time zone is GMT. GMT is a fuzzy term, it used to * referred both to UTC and UT1. */ private static boolean isGMTish(String name) { if (name.length() < 3) { return false; } char c1 = name.charAt(0); char c2 = name.charAt(1); char c3 = name.charAt(2); if ( !( (c1 == 'G' || c1 == 'g') && (c2 == 'M' || c2 == 'm') && (c3 == 'T' || c3 == 't') ) && !( (c1 == 'U' || c1 == 'u') && (c2 == 'T' || c2 == 't') && (c3 == 'C' || c3 == 'c') ) && !( (c1 == 'U' || c1 == 'u') && (c2 == 'T' || c2 == 't') && (c3 == '1' || c3 == '1') ) ) { return false; } if (name.length() == 3) { return true; } String offset = name.substring(3); if (offset.startsWith("+")) { return offset.equals("+0") || offset.equals("+00") || offset.equals("+00:00"); } else { return offset.equals("-0") || offset.equals("-00") || offset.equals("-00:00"); } } /** * Format a date, time or date+time with one of the ISO 8601 extended * formats. Examples of possible outputs: * {@code "2005-11-27T15:30:00+02:00"}, {@code "2005-11-27"}, * {@code "15:30:00Z"}. Note the {@code ":00"} in the time zone offset; * this is not required by ISO 8601, but included for compatibility with * the XML Schema date/time formats. * * This method is thread-safe. * * @param date the date to convert to ISO 8601 string * @param datePart whether the date part (year, month, day) will be included * or not * @param timePart whether the time part (hours, minutes, seconds, * milliseconds) will be included or not * @param offsetPart whether the time zone offset part will be included or * not. This will be shown as an offset to UTC (examples: * {@code "+01"}, {@code "-02"}, {@code "+04:30"}) or as {@code "Z"} * for UTC (and for UT1 and for GMT+00, since the Java platform * doesn't really care about the difference). * Note that this can't be {@code true} when {@code timePart} is * {@code false}, because ISO 8601 (2004) doesn't mention such * patterns. * @param accuracy tells which parts of the date/time to drop. The * {@code datePart} and {@code timePart} parameters are stronger than * this. Note that when {@link #ACCURACY_MILLISECONDS} is specified, * the milliseconds part will be displayed as fraction seconds * (like {@code "15:30.00.25"}) with the minimum number of * digits needed to show the milliseconds without precision lose. * Thus, if the milliseconds happen to be exactly 0, no fraction * seconds will be shown at all. * @param timeZone the time zone in which the date/time will be shown. (You * may find {@link DateUtil#UTC} handy here.) Note * that although date-only formats has no time zone offset part, * the result still depends on the time zone, as days start and end * at different points in time in different zones. * @param calendarFactory the factory that will create the calendar used * internally for calculations. The point of this parameter is that * creating a new calendar is relatively expensive, so it's desirable * to reuse calendars and only set their time and zone. (This was * tested on Sun JDK 1.6 x86 Win, where it gave 2x-3x speedup.) */ public static String dateToISO8601String( Date date, boolean datePart, boolean timePart, boolean offsetPart, int accuracy, TimeZone timeZone, DateToISO8601CalendarFactory calendarFactory) { if (!timePart && offsetPart) { throw new IllegalArgumentException( "ISO 8601:2004 doesn't specify any formats where the " + "offset is shown but the time isn't."); } if (timeZone == null) { timeZone = UTC; } GregorianCalendar cal = calendarFactory.get(timeZone, date); int maxLength; if (!timePart) { maxLength = 10; // YYYY-MM-DD } else { if (!datePart) { maxLength = 18; // HH:MM:SS.mmm+00:00 } else { maxLength = 10 + 1 + 18; } } char[] res = new char[maxLength]; int dstIdx = 0; if (datePart) { int x = cal.get(Calendar.YEAR); if (x > 0 && cal.get(Calendar.ERA) == GregorianCalendar.BC) { x = -x + 1; } if (x >= 0 && x < 9999) { res[dstIdx++] = (char) ('0' + x / 1000); res[dstIdx++] = (char) ('0' + x % 1000 / 100); res[dstIdx++] = (char) ('0' + x % 100 / 10); res[dstIdx++] = (char) ('0' + x % 10); } else { String yearString = String.valueOf(x); // Re-allocate buffer: maxLength = maxLength - 4 + yearString.length(); res = new char[maxLength]; for (int i = 0; i < yearString.length(); i++) { res[dstIdx++] = yearString.charAt(i); } } res[dstIdx++] = '-'; x = cal.get(Calendar.MONTH) + 1; dstIdx = append00(res, dstIdx, x); res[dstIdx++] = '-'; x = cal.get(Calendar.DAY_OF_MONTH); dstIdx = append00(res, dstIdx, x); if (timePart) { res[dstIdx++] = 'T'; } } if (timePart) { int x = cal.get(Calendar.HOUR_OF_DAY); dstIdx = append00(res, dstIdx, x); if (accuracy >= ACCURACY_MINUTES) { res[dstIdx++] = ':'; x = cal.get(Calendar.MINUTE); dstIdx = append00(res, dstIdx, x); if (accuracy >= ACCURACY_SECONDS) { res[dstIdx++] = ':'; x = cal.get(Calendar.SECOND); dstIdx = append00(res, dstIdx, x); if (accuracy >= ACCURACY_MILLISECONDS) { x = cal.get(Calendar.MILLISECOND); if (x != 0) { if (x > 999) { // Shouldn't ever happen... throw new RuntimeException( "Calendar.MILLISECOND > 999"); } res[dstIdx++] = '.'; do { res[dstIdx++] = (char) ('0' + (x / 100)); x = x % 100 * 10; } while (x != 0); } } } } } if (offsetPart) { if (timeZone == UTC) { res[dstIdx++] = 'Z'; } else { int dt = TIME_ZONE_OFFSET_CALCULATOR.getOffset(timeZone, date); boolean positive; if (dt < 0) { positive = false; dt = -dt; } else { positive = true; } dt /= 1000; int offS = dt % 60; dt /= 60; int offM = dt % 60; dt /= 60; int offH = dt; if (offS == 0 && offM == 0 && offH == 0) { res[dstIdx++] = 'Z'; } else { res[dstIdx++] = positive ? '+' : '-'; dstIdx = append00(res, dstIdx, offH); res[dstIdx++] = ':'; dstIdx = append00(res, dstIdx, offM); if (offS != 0) { res[dstIdx++] = ':'; dstIdx = append00(res, dstIdx, offS); } } } } return new String(res, 0, dstIdx); } /** * Appends a number between 0 and 99 padded to 2 digits. */ private static int append00(char[] res, int dstIdx, int x) { res[dstIdx++] = (char) ('0' + x / 10); res[dstIdx++] = (char) ('0' + x % 10); return dstIdx; } /** * Used internally by {@link DateUtil}; don't use it's implementations for * anything else. */ public interface DateToISO8601CalendarFactory { /** * Returns a {@link GregorianCalendar} with the desired time zone and * time and US locale. The returned calendar is used as read-only. * It's guaranteed that within a thread the instance returned last time * is not in use anymore when this method is called again. */ GregorianCalendar get(TimeZone tz, Date date); } /** * Non-thread-safe factory that hard-references a calendar internally. */ public static final class TrivialDateToISO8601CalendarFactory implements DateToISO8601CalendarFactory { private GregorianCalendar calendar; public GregorianCalendar get(TimeZone tz, Date date) { if (calendar == null) { calendar = new GregorianCalendar(tz, Locale.US); } else { calendar.setTimeZone(tz); } calendar.setTime(date); return calendar; } } interface TimeZoneOffsetCalculator { int getOffset(TimeZone tz, Date date); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/Collections12.java0000644000175000017500000001676411723544471027370 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.io.Serializable; import java.util.AbstractList; import java.util.AbstractMap; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; /** * Implementation of missing JDK 1.3 collection features for JDK 1.2 * @author Attila Szegedi * @version $Id: Collections12.java,v 1.2 2004/11/27 14:49:57 ddekany Exp $ */ public class Collections12 { public static final Map EMPTY_MAP = new EmptyMap(); private Collections12() { } private static final class EmptyMap extends AbstractMap implements Serializable { public int size() { return 0; } public boolean isEmpty() { return true; } public boolean containsKey(Object key) { return false; } public boolean containsValue(Object value) { return false; } public Object get(Object key) { return null; } public Set keySet() { return Collections.EMPTY_SET; } public Collection values() { return Collections.EMPTY_SET; } public Set entrySet() { return Collections.EMPTY_SET; } public boolean equals(Object o) { return (o instanceof Map) && ((Map) o).size() == 0; } public int hashCode() { return 0; } } public static Map singletonMap(Object key, Object value) { return new SingletonMap(key, value); } private static class SingletonMap extends AbstractMap implements Serializable { private final Object k, v; SingletonMap(Object key, Object value) { k = key; v = value; } public int size() { return 1; } public boolean isEmpty() { return false; } public boolean containsKey(Object key) { return eq(key, k); } public boolean containsValue(Object value) { return eq(value, v); } public Object get(Object key) { return (eq(key, k) ? v : null); } private transient Set keySet = null; private transient Set entrySet = null; private transient Collection values = null; public Set keySet() { if (keySet == null) keySet = Collections.singleton(k); return keySet; } public Set entrySet() { if (entrySet == null) entrySet = Collections.singleton(new ImmutableEntry(k, v)); return entrySet; } public Collection values() { if (values == null) values = Collections.singleton(v); return values; } private static class ImmutableEntry implements Map.Entry { final Object k; final Object v; ImmutableEntry(Object key, Object value) { k = key; v = value; } public Object getKey() { return k; } public Object getValue() { return v; } public Object setValue(Object value) { throw new UnsupportedOperationException(); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry) o; return eq(e.getKey(), k) && eq(e.getValue(), v); } public int hashCode() { return ( (k == null ? 0 : k.hashCode()) ^ (v == null ? 0 : v.hashCode())); } public String toString() { return k + "=" + v; } } } public static List singletonList(Object o) { return new SingletonList(o); } private static class SingletonList extends AbstractList implements Serializable { private final Object element; SingletonList(Object obj) { element = obj; } public int size() { return 1; } public boolean contains(Object obj) { return eq(obj, element); } public Object get(int index) { if (index != 0) throw new IndexOutOfBoundsException( "Index: " + index + ", Size: 1"); return element; } } private static boolean eq(Object o1, Object o2) { return (o1 == null ? o2 == null : o1.equals(o2)); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/StringUtil.java0000644000175000017500000014661011723544467027052 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import freemarker.core.Environment; import freemarker.core.ParseException; import freemarker.template.Template; /** * Some text related utilities. * * @version $Id: StringUtil.java,v 1.48 2005/06/01 22:39:08 ddekany Exp $ */ public class StringUtil { private static final char[] ESCAPES = createEscapes(); /* * For better performance most methods are folded down. Don't you scream... :) */ /** * HTML encoding (does not convert line breaks). * Replaces all '>' '<' '&' and '"' with entity reference */ public static String HTMLEnc(String s) { return XMLEncNA(s); } /** * XML Encoding. * Replaces all '>' '<' '&', "'" and '"' with entity reference */ public static String XMLEnc(String s) { return XMLOrXHTMLEnc(s, "'"); } /** * XHTML Encoding. * Replaces all '>' '<' '&', "'" and '"' with entity reference * suitable for XHTML decoding in common user agents (including legacy * user agents, which do not decode "'" to "'", so "'" is used * instead [see http://www.w3.org/TR/xhtml1/#C_16]) */ public static String XHTMLEnc(String s) { return XMLOrXHTMLEnc(s, "'"); } private static String XMLOrXHTMLEnc(String s, String aposReplacement) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '<' || c == '>' || c == '&' || c == '"' || c == '\'') { StringBuffer b = new StringBuffer(s.substring(0, i)); switch (c) { case '<': b.append("<"); break; case '>': b.append(">"); break; case '&': b.append("&"); break; case '"': b.append("""); break; case '\'': b.append(aposReplacement); break; } i++; int next = i; while (i < ln) { c = s.charAt(i); if (c == '<' || c == '>' || c == '&' || c == '"' || c == '\'') { b.append(s.substring(next, i)); switch (c) { case '<': b.append("<"); break; case '>': b.append(">"); break; case '&': b.append("&"); break; case '"': b.append("""); break; case '\'': b.append(aposReplacement); break; } next = i + 1; } i++; } if (next < ln) b.append(s.substring(next)); s = b.toString(); break; } // if c == } // for return s; } /** * XML encoding without replacing apostrophes. * @see #XMLEnc(String) */ public static String XMLEncNA(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '<' || c == '>' || c == '&' || c == '"') { StringBuffer b = new StringBuffer(s.substring(0, i)); switch (c) { case '<': b.append("<"); break; case '>': b.append(">"); break; case '&': b.append("&"); break; case '"': b.append("""); break; } i++; int next = i; while (i < ln) { c = s.charAt(i); if (c == '<' || c == '>' || c == '&' || c == '"') { b.append(s.substring(next, i)); switch (c) { case '<': b.append("<"); break; case '>': b.append(">"); break; case '&': b.append("&"); break; case '"': b.append("""); break; } next = i + 1; } i++; } if (next < ln) b.append(s.substring(next)); s = b.toString(); break; } // if c == } // for return s; } /** * XML encoding for attributes valies quoted with " (not with '!). * Also can be used for HTML attributes that are quoted with ". * @see #XMLEnc(String) */ public static String XMLEncQAttr(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '<' || c == '&' || c == '"') { StringBuffer b = new StringBuffer(s.substring(0, i)); switch (c) { case '<': b.append("<"); break; case '&': b.append("&"); break; case '"': b.append("""); break; } i++; int next = i; while (i < ln) { c = s.charAt(i); if (c == '<' || c == '&' || c == '"') { b.append(s.substring(next, i)); switch (c) { case '<': b.append("<"); break; case '&': b.append("&"); break; case '"': b.append("""); break; } next = i + 1; } i++; } if (next < ln) { b.append(s.substring(next)); } s = b.toString(); break; } // if c == } // for return s; } /** * XML encoding without replacing apostrophes and quotation marks and * greater-thans (except in {@code ]]>}). * @see #XMLEnc(String) */ public static String XMLEncNQG(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '<' || (c == '>' && i > 1 && s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']') || c == '&') { StringBuffer b = new StringBuffer(s.substring(0, i)); switch (c) { case '<': b.append("<"); break; case '>': b.append(">"); break; case '&': b.append("&"); break; default: throw new RuntimeException("Bug: unexpected char"); } i++; int next = i; while (i < ln) { c = s.charAt(i); if (c == '<' || (c == '>' && i > 1 && s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']') || c == '&') { b.append(s.substring(next, i)); switch (c) { case '<': b.append("<"); break; case '>': b.append(">"); break; case '&': b.append("&"); break; default: throw new RuntimeException("Bug: unexpected char"); } next = i + 1; } i++; } if (next < ln) { b.append(s.substring(next)); } s = b.toString(); break; } // if c == } // for return s; } /** * Rich Text Format encoding (does not replace line breaks). * Escapes all '\' '{' '}' and '"' */ public static String RTFEnc(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '\\' || c == '{' || c == '}') { StringBuffer b = new StringBuffer(s.substring(0, i)); switch (c) { case '\\': b.append("\\\\"); break; case '{': b.append("\\{"); break; case '}': b.append("\\}"); break; } i++; int next = i; while (i < ln) { c = s.charAt(i); if (c == '\\' || c == '{' || c == '}') { b.append(s.substring(next, i)); switch (c) { case '\\': b.append("\\\\"); break; case '{': b.append("\\{"); break; case '}': b.append("\\}"); break; } next = i + 1; } i++; } if (next < ln) b.append(s.substring(next)); s = b.toString(); break; } // if c == } // for return s; } /** * URL encoding (like%20this). */ public static String URLEnc(String s, String charset) throws UnsupportedEncodingException { int ln = s.length(); int i; for (i = 0; i < ln; i++) { char c = s.charAt(i); if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' || c == '-' || c == '.' || c == '!' || c == '~' || c >= '\'' && c <= '*')) { break; } } if (i == ln) { // Nothing to escape return s; } StringBuffer b = new StringBuffer(ln + ln / 3 + 2); b.append(s.substring(0, i)); int encstart = i; for (i++; i < ln; i++) { char c = s.charAt(i); if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_' || c == '-' || c == '.' || c == '!' || c == '~' || c >= '\'' && c <= '*') { if (encstart != -1) { byte[] o = s.substring(encstart, i).getBytes(charset); for (int j = 0; j < o.length; j++) { b.append('%'); byte bc = o[j]; int c1 = bc & 0x0F; int c2 = (bc >> 4) & 0x0F; b.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A')); b.append((char) (c1 < 10 ? c1 + '0' : c1 - 10 + 'A')); } encstart = -1; } b.append(c); } else { if (encstart == -1) { encstart = i; } } } if (encstart != -1) { byte[] o = s.substring(encstart, i).getBytes(charset); for (int j = 0; j < o.length; j++) { b.append('%'); byte bc = o[j]; int c1 = bc & 0x0F; int c2 = (bc >> 4) & 0x0F; b.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A')); b.append((char) (c1 < 10 ? c1 + '0' : c1 - 10 + 'A')); } } return b.toString(); } private static char[] createEscapes() { char[] escapes = new char['\\' + 1]; for(int i = 0; i < 32; ++i) { escapes[i] = 1; } escapes['\\'] = '\\'; escapes['\''] = '\''; escapes['"'] = '"'; escapes['<'] = 'l'; escapes['>'] = 'g'; escapes['&'] = 'a'; escapes['\b'] = 'b'; escapes['\t'] = 't'; escapes['\n'] = 'n'; escapes['\f'] = 'f'; escapes['\r'] = 'r'; escapes['$'] = '$'; return escapes; } public static String FTLStringLiteralEnc(String s) { StringBuffer buf = null; int l = s.length(); int el = ESCAPES.length; for(int i = 0; i < l; i++) { char c = s.charAt(i); if(c < el) { char escape = ESCAPES[c]; switch(escape) { case 0: { if (buf != null) { buf.append(c); } break; } case 1: { if (buf == null) { buf = new StringBuffer(s.length() + 3); buf.append(s.substring(0, i)); } // hex encoding for characters below 0x20 // that have no other escape representation buf.append("\\x00"); int c2 = (c >> 4) & 0x0F; c = (char) (c & 0x0F); buf.append((char) (c2 < 10 ? c2 + '0' : c2 - 10 + 'A')); buf.append((char) (c < 10 ? c + '0' : c - 10 + 'A')); break; } default: { if (buf == null) { buf = new StringBuffer(s.length() + 2); buf.append(s.substring(0, i)); } buf.append('\\'); buf.append(escape); } } } else { if (buf != null) { buf.append(c); } } } return buf == null ? s : buf.toString(); } /** * FTL string literal decoding. * * \\, \", \', \n, \t, \r, \b and \f will be replaced according to * Java rules. In additional, it knows \g, \l, \a and \{ which are * replaced with <, >, & and { respectively. * \x works as hexadecimal character code escape. The character * codes are interpreted according to UCS basic plane (Unicode). * "f\x006Fo", "f\x06Fo" and "f\x6Fo" will be "foo". * "f\x006F123" will be "foo123" as the maximum number of digits is 4. * * All other \X (where X is any character not mentioned above or End-of-string) * will cause a ParseException. * * @param s String literal without the surrounding quotation marks * @return String with all escape sequences resolved * @throws ParseException if there string contains illegal escapes */ public static String FTLStringLiteralDec(String s) throws ParseException { int idx = s.indexOf('\\'); if (idx == -1) { return s; } int lidx = s.length() - 1; int bidx = 0; StringBuffer buf = new StringBuffer(lidx); do { buf.append(s.substring(bidx, idx)); if (idx >= lidx) { throw new ParseException("The last character of string literal is backslash", 0,0); } char c = s.charAt(idx + 1); switch (c) { case '"': buf.append('"'); bidx = idx + 2; break; case '\'': buf.append('\''); bidx = idx + 2; break; case '\\': buf.append('\\'); bidx = idx + 2; break; case 'n': buf.append('\n'); bidx = idx + 2; break; case 'r': buf.append('\r'); bidx = idx + 2; break; case 't': buf.append('\t'); bidx = idx + 2; break; case 'f': buf.append('\f'); bidx = idx + 2; break; case 'b': buf.append('\b'); bidx = idx + 2; break; case 'g': buf.append('>'); bidx = idx + 2; break; case 'l': buf.append('<'); bidx = idx + 2; break; case 'a': buf.append('&'); bidx = idx + 2; break; case '{': buf.append('{'); bidx = idx + 2; break; case 'x': { idx += 2; int x = idx; int y = 0; int z = lidx > idx + 3 ? idx + 3 : lidx; while (idx <= z) { char b = s.charAt(idx); if (b >= '0' && b <= '9') { y <<= 4; y += b - '0'; } else if (b >= 'a' && b <= 'f') { y <<= 4; y += b - 'a' + 10; } else if (b >= 'A' && b <= 'F') { y <<= 4; y += b - 'A' + 10; } else { break; } idx++; } if (x < idx) { buf.append((char) y); } else { throw new ParseException("Invalid \\x escape in a string literal",0,0); } bidx = idx; break; } default: throw new ParseException("Invalid escape sequence (\\" + c + ") in a string literal",0,0); } idx = s.indexOf('\\', bidx); } while (idx != -1); buf.append(s.substring(bidx)); return buf.toString(); } public static Locale deduceLocale(String input) { Locale locale = Locale.getDefault(); if (input.charAt(0) == '"') input = input.substring(1, input.length() -1); StringTokenizer st = new StringTokenizer(input, ",_ "); String lang = "", country = ""; if (st.hasMoreTokens()) { lang = st.nextToken(); } if (st.hasMoreTokens()) { country = st.nextToken(); } if (!st.hasMoreTokens()) { locale = new Locale(lang, country); } else { locale = new Locale(lang, country, st.nextToken()); } return locale; } public static String capitalize(String s) { StringTokenizer st = new StringTokenizer(s, " \t\r\n", true); StringBuffer buf = new StringBuffer(s.length()); while (st.hasMoreTokens()) { String tok = st.nextToken(); buf.append(tok.substring(0, 1).toUpperCase()); buf.append(tok.substring(1).toLowerCase()); } return buf.toString(); } public static boolean getYesNo(String s) { if (s.startsWith("\"")) { s = s.substring(1, s.length() -1); } if (s.equalsIgnoreCase("n") || s.equalsIgnoreCase("no") || s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false")) { return false; } else if (s.equalsIgnoreCase("y") || s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("t") || s.equalsIgnoreCase("true")) { return true; } throw new IllegalArgumentException("Illegal boolean value: " + s); } /** * Splits a string at the specified character. */ public static String[] split(String s, char c) { int i, b, e; int cnt; String res[]; int ln = s.length(); i = 0; cnt = 1; while ((i = s.indexOf(c, i)) != -1) { cnt++; i++; } res = new String[cnt]; i = 0; b = 0; while (b <= ln) { e = s.indexOf(c, b); if (e == -1) e = ln; res[i++] = s.substring(b, e); b = e + 1; } return res; } /** * Splits a string at the specified string. */ public static String[] split(String s, String sep, boolean caseInsensitive) { String splitString = caseInsensitive ? sep.toLowerCase() : sep; String input = caseInsensitive ? s.toLowerCase() : s; int i, b, e; int cnt; String res[]; int ln = s.length(); int sln = sep.length(); if (sln == 0) throw new IllegalArgumentException( "The separator string has 0 length"); i = 0; cnt = 1; while ((i = input.indexOf(splitString, i)) != -1) { cnt++; i += sln; } res = new String[cnt]; i = 0; b = 0; while (b <= ln) { e = input.indexOf(splitString, b); if (e == -1) e = ln; res[i++] = s.substring(b, e); b = e + sln; } return res; } /** * Replaces all occurrences of a sub-string in a string. * @param text The string where it will replace oldsub with * newsub. * @return String The string after the replacements. */ public static String replace(String text, String oldsub, String newsub, boolean caseInsensitive, boolean firstOnly) { StringBuffer buf; int tln; int oln = oldsub.length(); if (oln == 0) { int nln = newsub.length(); if (nln == 0) { return text; } else { if (firstOnly) { return newsub + text; } else { tln = text.length(); buf = new StringBuffer(tln + (tln + 1) * nln); buf.append(newsub); for (int i = 0; i < tln; i++) { buf.append(text.charAt(i)); buf.append(newsub); } return buf.toString(); } } } else { oldsub = caseInsensitive ? oldsub.toLowerCase() : oldsub; String input = caseInsensitive ? text.toLowerCase() : text; int e = input.indexOf(oldsub); if (e == -1) { return text; } int b = 0; tln = text.length(); buf = new StringBuffer( tln + Math.max(newsub.length() - oln, 0) * 3); do { buf.append(text.substring(b, e)); buf.append(newsub); b = e + oln; e = input.indexOf(oldsub, b); } while (e != -1 && !firstOnly); buf.append(text.substring(b)); return buf.toString(); } } /** * Removes the line-break from the end of the string. */ public static String chomp(String s) { if (s.endsWith("\r\n")) return s.substring(0, s.length() - 2); if (s.endsWith("\r") || s.endsWith("\n")) return s.substring(0, s.length() - 1); return s; } /** * Converts the parameter with toString (if not * null)and passes it to {@link #jQuote(String)}. */ public static String jQuote(Object obj) { return jQuote(obj != null ? obj.toString() : null); } /** * Quotes string as Java Language string literal. * Returns string "null" if s * is null. */ public static String jQuote(String s) { if (s == null) { return "null"; } int ln = s.length(); StringBuffer b = new StringBuffer(ln + 4); b.append('"'); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '"') { b.append("\\\""); } else if (c == '\\') { b.append("\\\\"); } else if (c < 0x20) { if (c == '\n') { b.append("\\n"); } else if (c == '\r') { b.append("\\r"); } else if (c == '\f') { b.append("\\f"); } else if (c == '\b') { b.append("\\b"); } else if (c == '\t') { b.append("\\t"); } else { b.append("\\u00"); int x = c / 0x10; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); x = c & 0xF; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); } } else { b.append(c); } } // for each characters b.append('"'); return b.toString(); } /** * Converts the parameter with toString (if not * null)and passes it to {@link #jQuoteNoXSS(String)}. */ public static String jQuoteNoXSS(Object obj) { return jQuoteNoXSS(obj != null ? obj.toString() : null); } /** * Same as {@link #jQuoteNoXSS(String)} but also escapes '<' * as \u003C. This is used for log messages to prevent XSS * on poorly written Web-based log viewers. */ public static String jQuoteNoXSS(String s) { if (s == null) { return "null"; } int ln = s.length(); StringBuffer b = new StringBuffer(ln + 4); b.append('"'); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '"') { b.append("\\\""); } else if (c == '\\') { b.append("\\\\"); } else if (c == '<') { b.append("\\u003C"); } else if (c < 0x20) { if (c == '\n') { b.append("\\n"); } else if (c == '\r') { b.append("\\r"); } else if (c == '\f') { b.append("\\f"); } else if (c == '\b') { b.append("\\b"); } else if (c == '\t') { b.append("\\t"); } else { b.append("\\u00"); int x = c / 0x10; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); x = c & 0xF; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); } } else { b.append(c); } } // for each characters b.append('"'); return b.toString(); } /** * Escapes the String with the escaping rules of Java language * string literals, so it is safe to insert the value into a string literal. * The resulting string will not be quoted. * *

All characters under UCS code point 0x20 will be escaped. * Where they have no dedicated escape sequence in Java, they will * be replaced with hexadecimal escape (\uXXXX). * * @see #jQuote(String) */ public static String javaStringEnc(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '"' || c == '\\' || c < 0x20) { StringBuffer b = new StringBuffer(ln + 4); b.append(s.substring(0, i)); while (true) { if (c == '"') { b.append("\\\""); } else if (c == '\\') { b.append("\\\\"); } else if (c < 0x20) { if (c == '\n') { b.append("\\n"); } else if (c == '\r') { b.append("\\r"); } else if (c == '\f') { b.append("\\f"); } else if (c == '\b') { b.append("\\b"); } else if (c == '\t') { b.append("\\t"); } else { b.append("\\u00"); int x = c / 0x10; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'a')); x = c & 0xF; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'a')); } } else { b.append(c); } i++; if (i >= ln) { return b.toString(); } c = s.charAt(i); } } // if has to be escaped } // for each characters return s; } /** * Escapes a String according the JavaScript string literal * escaping rules. The resulting string will not be quoted. * *

It escapes both ' and ". * In additional it escapes > as \> (to avoid * </script>). * *

All characters under UCS code point 0x20 will be escaped. * Where they have no dedicated escape sequence in JavaScript, they will * be replaced with hexadecimal escape (\uXXXX). */ public static String javaScriptStringEnc(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '"' || c == '\'' || c == '\\' || c == '>' || c < 0x20) { StringBuffer b = new StringBuffer(ln + 4); b.append(s.substring(0, i)); while (true) { if (c == '"') { b.append("\\\""); } else if (c == '\'') { b.append("\\'"); } else if (c == '\\') { b.append("\\\\"); } else if (c == '>') { b.append("\\>"); } else if (c < 0x20) { if (c == '\n') { b.append("\\n"); } else if (c == '\r') { b.append("\\r"); } else if (c == '\f') { b.append("\\f"); } else if (c == '\b') { b.append("\\b"); } else if (c == '\t') { b.append("\\t"); } else { b.append("\\x"); int x = c / 0x10; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); x = c & 0xF; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); } } else { b.append(c); } i++; if (i >= ln) { return b.toString(); } c = s.charAt(i); } } // if has to be escaped } // for each characters return s; } /** * Escapes a String according the JSON string literal * escaping rules. The resulting string will not be quoted; * the caller have to ensure that they are there in the final output. * *

Beware, it doesn't escape ', as JSON string must be delimited with * ", and JSON has no \' escape either! * *

It will escape / as \/ if it's after <, * to avoid </script>. * *

It will escape > as \u003E if it's after * ]], to avoid closing a CDATA section. * *

All characters under UCS code point 0x20 will be escaped. * Where they have no dedicated escape sequence in JSON, they will * be replaced with hexadecimal escape (\uXXXX). */ public static String jsonStringEnc(String s) { int ln = s.length(); for (int i = 0; i < ln; i++) { char c = s.charAt(i); if (c == '"' || c == '\\' || c < 0x20 || (c == '/' && i > 0 && s.charAt(i -1) == '<') || (c == '>' && i > 1 && s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']')) { StringBuffer b = new StringBuffer(ln + 4); b.append(s.substring(0, i)); while (true) { if (c == '"') { b.append("\\\""); } else if (c == '\\') { b.append("\\\\"); } else if (c == '/' && i > 0 && s.charAt(i -1) == '<') { b.append("\\/"); } else if (c == '>' && i > 1 && s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']') { b.append("\\u003E"); } else if (c < 0x20) { if (c == '\n') { b.append("\\n"); } else if (c == '\r') { b.append("\\r"); } else if (c == '\f') { b.append("\\f"); } else if (c == '\b') { b.append("\\b"); } else if (c == '\t') { b.append("\\t"); } else { b.append("\\u00"); int x = c / 0x10; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); x = c & 0xF; b.append((char) (x < 0xA ? x + '0' : x - 0xA + 'A')); } } else { b.append(c); } i++; if (i >= ln) { return b.toString(); } c = s.charAt(i); } } // if has to be escaped } // for each characters return s; } /** * Parses a name-value pair list, where the pairs are separated with comma, * and the name and value is separated with colon. * The keys and values can contain only letters, digits and _. They * can't be quoted. White-space around the keys and values are ignored. The * value can be omitted if defaultValue is not null. When a * value is omitted, then the colon after the key must be omitted as well. * The same key can't be used for multiple times. * * @param s the string to parse. * For example: "strong:100, soft:900". * @param defaultValue the value used when the value is omitted in a * key-value pair. * * @return the map that contains the name-value pairs. * * @throws java.text.ParseException if the string is not a valid name-value * pair list. */ public static Map parseNameValuePairList(String s, String defaultValue) throws java.text.ParseException { Map map = new HashMap(); char c = ' '; int ln = s.length(); int p = 0; int keyStart; int valueStart; String key; String value; fetchLoop: while (true) { // skip ws while (p < ln) { c = s.charAt(p); if (!Character.isWhitespace(c)) { break; } p++; } if (p == ln) { break fetchLoop; } keyStart = p; // seek key end while (p < ln) { c = s.charAt(p); if (!(Character.isLetterOrDigit(c) || c == '_')) { break; } p++; } if (keyStart == p) { throw new java.text.ParseException( "Expecting letter, digit or \"_\" " + "here, (the first character of the key) but found " + jQuote(String.valueOf(c)) + " at position " + p + ".", p); } key = s.substring(keyStart, p); // skip ws while (p < ln) { c = s.charAt(p); if (!Character.isWhitespace(c)) { break; } p++; } if (p == ln) { if (defaultValue == null) { throw new java.text.ParseException( "Expecting \":\", but reached " + "the end of the string " + " at position " + p + ".", p); } value = defaultValue; } else if (c != ':') { if (defaultValue == null || c != ',') { throw new java.text.ParseException( "Expecting \":\" here, but found " + jQuote(String.valueOf(c)) + " at position " + p + ".", p); } // skip "," p++; value = defaultValue; } else { // skip ":" p++; // skip ws while (p < ln) { c = s.charAt(p); if (!Character.isWhitespace(c)) { break; } p++; } if (p == ln) { throw new java.text.ParseException( "Expecting the value of the key " + "here, but reached the end of the string " + " at position " + p + ".", p); } valueStart = p; // seek value end while (p < ln) { c = s.charAt(p); if (!(Character.isLetterOrDigit(c) || c == '_')) { break; } p++; } if (valueStart == p) { throw new java.text.ParseException( "Expecting letter, digit or \"_\" " + "here, (the first character of the value) " + "but found " + jQuote(String.valueOf(c)) + " at position " + p + ".", p); } value = s.substring(valueStart, p); // skip ws while (p < ln) { c = s.charAt(p); if (!Character.isWhitespace(c)) { break; } p++; } // skip "," if (p < ln) { if (c != ',') { throw new java.text.ParseException( "Excpecting \",\" or the end " + "of the string here, but found " + jQuote(String.valueOf(c)) + " at position " + p + ".", p); } else { p++; } } } // store the key-value pair if (map.put(key, value) != null) { throw new java.text.ParseException( "Dublicated key: " + jQuote(key), keyStart); } } return map; } /** * @return whether the name is a valid XML tagname. * (This routine might only be 99% accurate. Should maybe REVISIT) */ static public boolean isXMLID(String name) { for (int i=0; ileftPad('ABC', 9, '1234') * returns "123412ABC". * * @param s the string that will be padded. * @param minLength the length to reach. * @param filling the filling pattern. Must be at least 1 characters long. * Can't be null. */ public static String leftPad(String s, int minLength, String filling) { int ln = s.length(); if (minLength <= ln) { return s; } StringBuffer res = new StringBuffer(minLength); int dif = minLength - ln; int fln = filling.length(); if (fln == 0) { throw new IllegalArgumentException( "The \"filling\" argument can't be 0 length string."); } int cnt = dif / fln; for (int i = 0; i < cnt; i++) { res.append(filling); } cnt = dif % fln; for (int i = 0; i < cnt; i++) { res.append(filling.charAt(i)); } res.append(s); return res.toString(); } /** * Pads the string at the right with spaces until it reaches the desired * length. If the string is longer than this length, then it returns the * unchanged string. * * @param s the string that will be padded. * @param minLength the length to reach. */ public static String rightPad(String s, int minLength) { return rightPad(s, minLength, ' '); } /** * Pads the string at the right with the specified character until it * reaches the desired length. If the string is longer than this length, * then it returns the unchanged string. * * @param s the string that will be padded. * @param minLength the length to reach. * @param filling the filling pattern. */ public static String rightPad(String s, int minLength, char filling) { int ln = s.length(); if (minLength <= ln) { return s; } StringBuffer res = new StringBuffer(minLength); res.append(s); int dif = minLength - ln; for (int i = 0; i < dif; i++) { res.append(filling); } return res.toString(); } /** * Pads the string at the right with a filling pattern until it reaches the * desired length. If the string is longer than this length, then it returns * the unchanged string. For example: rightPad('ABC', 9, '1234') * returns "ABC412341". Note that the filling pattern is * started as if you overlay "123412341" with the left-aligned * "ABC", so it starts with "4". * * @param s the string that will be padded. * @param minLength the length to reach. * @param filling the filling pattern. Must be at least 1 characters long. * Can't be null. */ public static String rightPad(String s, int minLength, String filling) { int ln = s.length(); if (minLength <= ln) { return s; } StringBuffer res = new StringBuffer(minLength); res.append(s); int dif = minLength - ln; int fln = filling.length(); if (fln == 0) { throw new IllegalArgumentException( "The \"filling\" argument can't be 0 length string."); } int start = ln % fln; int end = fln - start <= dif ? fln : start + dif; for (int i = start; i < end; i++) { res.append(filling.charAt(i)); } dif -= end - start; int cnt = dif / fln; for (int i = 0; i < cnt; i++) { res.append(filling); } cnt = dif % fln; for (int i = 0; i < cnt; i++) { res.append(filling.charAt(i)); } return res.toString(); } /** * Converts a version number string to an integer for easy comparison. * The version number must start with numbers separated with * dots. There can be any number of such dot-separated numbers, but only * the first three will be considered. After the numbers arbitrary text can * follow, and will be ignored. * * The string will be trimmed before interpretation. * * @return major * 1000000 + minor * 1000 + micro */ public static int versionStringToInt(String version) { version = version.trim(); int[] parts = new int[3]; int partIdx = 0; boolean valid = false; for (int i = 0; i < version.length(); i++) { char c = version.charAt(i); if (c >= '0' && c <= '9') { parts[partIdx] = parts[partIdx] * 10 + (c - '0'); valid = true; } else { if (c == '.') { if (partIdx == 2) break; else partIdx++; } else { break; } } } if (!valid) throw new IllegalArgumentException( "A version number string " + jQuote(version) + " must start with a number."); return parts[0] * 1000000 + parts[1] * 1000 + parts[2]; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/DeepUnwrap.java0000644000175000017500000002167211723544471027013 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import java.util.ArrayList; import java.util.HashMap; import freemarker.core.Environment; import freemarker.ext.util.WrapperTemplateModel; import freemarker.template.AdapterTemplateModel; import freemarker.template.ObjectWrapper; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelIterator; import freemarker.template.TemplateNumberModel; import freemarker.template.TemplateScalarModel; import freemarker.template.TemplateSequenceModel; /** * Utility methods for unwrapping {@link TemplateModel}-s. * @author Attila Szegedi * @version $Id: DeepUnwrap.java,v 1.6 2005/06/16 18:13:58 ddekany Exp $ */ public class DeepUnwrap { private static final Class OBJECT_CLASS = Object.class; /** * Unwraps {@link TemplateModel}-s recursively. * The converting of the {@link TemplateModel} object happens with the following rules: *

    *
  1. If the object implements {@link AdapterTemplateModel}, then the result * of {@link AdapterTemplateModel#getAdaptedObject(Class)} for Object.class is returned. *
  2. If the object implements {@link WrapperTemplateModel}, then the result * of {@link WrapperTemplateModel#getWrappedObject()} is returned. *
  3. If the object is identical to the null model of the current object * wrapper, null is returned. *
  4. If the object implements {@link TemplateScalarModel}, then the result * of {@link TemplateScalarModel#getAsString()} is returned. *
  5. If the object implements {@link TemplateNumberModel}, then the result * of {@link TemplateNumberModel#getAsNumber()} is returned. *
  6. If the object implements {@link TemplateDateModel}, then the result * of {@link TemplateDateModel#getAsDate()} is returned. *
  7. If the object implements {@link TemplateBooleanModel}, then the result * of {@link TemplateBooleanModel#getAsBoolean()} is returned. *
  8. If the object implements {@link TemplateSequenceModel} or * {@link TemplateCollectionModel}, then a java.util.ArrayList is * constructed from the subvariables, and each subvariable is unwrapped with * the rules described here (recursive unwrapping). *
  9. If the object implements {@link TemplateHashModelEx}, then a * java.util.HashMap is constructed from the subvariables, and each * subvariable is unwrapped with the rules described here (recursive unwrapping). *
  10. Throw a TemplateModelException, because it doesn't know how to * unwrap the object. *
*/ public static Object unwrap(TemplateModel model) throws TemplateModelException { return unwrap(model, false); } /** * Same as {@link #unwrap(TemplateModel)}, but it doesn't throw exception * if it doesn't know how to unwrap the model, but rather returns it as-is. * @since 2.3.14 */ public static Object permissiveUnwrap(TemplateModel model) throws TemplateModelException { return unwrap(model, true); } /** * @deprecated the name of this method is mistyped. Use * {@link #permissiveUnwrap(TemplateModel)} instead. */ public static Object premissiveUnwrap(TemplateModel model) throws TemplateModelException { return unwrap(model, true); } private static Object unwrap(TemplateModel model, boolean permissive) throws TemplateModelException { Environment env = Environment.getCurrentEnvironment(); TemplateModel nullModel = null; if(env != null) { ObjectWrapper wrapper = env.getObjectWrapper(); if(wrapper != null) { nullModel = wrapper.wrap(null); } } return unwrap(model, nullModel, permissive); } private static Object unwrap(TemplateModel model, TemplateModel nullModel, boolean permissive) throws TemplateModelException { if(model instanceof AdapterTemplateModel) { return ((AdapterTemplateModel)model).getAdaptedObject(OBJECT_CLASS); } if (model instanceof WrapperTemplateModel) { return ((WrapperTemplateModel)model).getWrappedObject(); } if(model == nullModel) { return null; } if(model instanceof TemplateScalarModel) { return ((TemplateScalarModel)model).getAsString(); } if(model instanceof TemplateNumberModel) { return ((TemplateNumberModel)model).getAsNumber(); } if(model instanceof TemplateDateModel) { return ((TemplateDateModel)model).getAsDate(); } if(model instanceof TemplateBooleanModel) { return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; } if(model instanceof TemplateSequenceModel) { TemplateSequenceModel seq = (TemplateSequenceModel)model; ArrayList list = new ArrayList(seq.size()); for(int i = 0; i < seq.size(); ++i) { list.add(unwrap(seq.get(i), nullModel, permissive)); } return list; } if(model instanceof TemplateCollectionModel) { TemplateCollectionModel coll = (TemplateCollectionModel)model; ArrayList list = new ArrayList(); TemplateModelIterator it = coll.iterator(); while(it.hasNext()) { list.add(unwrap(it.next(), nullModel, permissive)); } return list; } if(model instanceof TemplateHashModelEx) { TemplateHashModelEx hash = (TemplateHashModelEx)model; HashMap map = new HashMap(); TemplateModelIterator keys = hash.keys().iterator(); while(keys.hasNext()) { String key = (String)unwrap(keys.next(), nullModel, permissive); map.put(key, unwrap(hash.get(key), nullModel, permissive)); } return map; } if (permissive) { return model; } throw new TemplateModelException("Cannot deep-unwrap model of type " + model.getClass().getName()); } }libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/UnrecognizedTimeZoneException.java0000644000175000017500000000610711723544472032724 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; /** * Indicates that the time zone name is not recognized. */ public class UnrecognizedTimeZoneException extends Exception { private final String timeZoneName; public UnrecognizedTimeZoneException(String timeZoneName) { super("Unrecognized time zone: " + StringUtil.jQuote(timeZoneName)); this.timeZoneName = timeZoneName; } public String getTimeZoneName() { return timeZoneName; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/NormalizeNewlines.java0000644000175000017500000001221311723544471030375 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import freemarker.template.TemplateTransformModel; import java.io.*; import java.util.Map; /** *

Transformer that supports FreeMarker legacy behavior: all newlines appearing * within the transformed area will be transformed into the platform's default * newline. Unlike the old behavior, however, newlines generated by the data * model are also converted. Legacy behavior was to leave newlines in the * data model unaltered.

* *

Usage:
* From java:

*
 * SimpleHash root = new SimpleHash();
 *
 * root.put( "normalizeNewlines", new freemarker.template.utility.NormalizeNewlines() );
 *
 * ...
 * 
* *

From your FreeMarker template:

*
 * <transform normalizeNewlines>
 *   <html>
 *   <head>
 *   ...
 *   <p>This template has all newlines normalized to the current platform's
 *   default.</p>
 *   ...
 *   </body>
 *   </html>
 * </transform>
 * 
* * * @version $Id: NormalizeNewlines.java,v 1.29 2003/04/11 20:57:32 revusky Exp $ */ public class NormalizeNewlines implements TemplateTransformModel { public Writer getWriter(final Writer out, final Map args) { final StringBuffer buf = new StringBuffer(); return new Writer() { public void write(char cbuf[], int off, int len) { buf.append(cbuf, off, len); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { StringReader sr = new StringReader(buf.toString()); StringWriter sw = new StringWriter(); transform(sr, sw); out.write(sw.toString()); } }; } /** * Performs newline normalization on FreeMarker output. * * @param in the input to be transformed * @param out the destination of the transformation */ public void transform(Reader in, Writer out) throws IOException { BufferedReader br = (in instanceof BufferedReader) ? (BufferedReader) in : new BufferedReader(in); PrintWriter pw = (out instanceof PrintWriter) ? (PrintWriter) out : new PrintWriter(out); String line = br.readLine(); if (line != null) { if ( line.length() > 0 ) { pw.println(line); } } while ((line = br.readLine()) != null) { pw.println(line); } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/DOMNodeModel.java0000644000175000017500000002573311723544470027150 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template.utility; import freemarker.template.*; import org.w3c.dom.*; import java.util.*; /** * A convenient wrapper class for wrapping a Node in the W3C DOM API. * @author Jonathan Revusky */ public class DOMNodeModel implements TemplateHashModel { static private HashMap equivalenceTable = new HashMap(); static { equivalenceTable.put("*", "children"); equivalenceTable.put("@*", "attributes"); } private Node node; private HashMap cache = new HashMap(); public DOMNodeModel(Node node) { this.node = node; } public TemplateModel get(String key) throws TemplateModelException { TemplateModel result = null; if (equivalenceTable.containsKey(key)) { key = (String) equivalenceTable.get(key); } if (cache.containsKey(key)) { result = (TemplateModel) cache.get(key); } if (result == null) { if ("attributes".equals(key)) { NamedNodeMap attributes = node.getAttributes(); if (attributes != null) { SimpleHash hash = new SimpleHash(); for (int i = 0; iThese constants should be stored in the {@link TemplateModel} * sub-interfaces, but for bacward compatibility they are stored here instead. * Starting from FreeMarker 2.4 they should be copyed (not moved!) into the * {@link TemplateModel} sub-interfaces, and this class should be marked as * deprecated.

* * @version $Id: Constants.java,v 1.2 2004/11/28 12:58:34 ddekany Exp $ */ public class Constants { public static final TemplateBooleanModel TRUE = TemplateBooleanModel.TRUE; public static final TemplateBooleanModel FALSE = TemplateBooleanModel.FALSE; public static final TemplateScalarModel EMPTY_STRING = (TemplateScalarModel) TemplateScalarModel.EMPTY_STRING; public static final TemplateNumberModel ZERO = new SimpleNumber(0); public static final TemplateNumberModel ONE = new SimpleNumber(1); public static final TemplateNumberModel MINUS_ONE = new SimpleNumber(-1); public static final TemplateModelIterator EMPTY_ITERATOR = new TemplateModelIterator() { public TemplateModel next() throws TemplateModelException { throw new TemplateModelException("The collection has no more elements."); } public boolean hasNext() throws TemplateModelException { return false; } }; public static final TemplateCollectionModel EMPTY_COLLECTION = new TemplateCollectionModel() { public TemplateModelIterator iterator() throws TemplateModelException { return EMPTY_ITERATOR; } }; public static final TemplateSequenceModel EMPTY_SEQUENCE = new TemplateSequenceModel() { public TemplateModel get(int index) throws TemplateModelException { return null; } public int size() throws TemplateModelException { return 0; } }; public static final TemplateHashModelEx EMPTY_HASH = new TemplateHashModelEx() { public int size() throws TemplateModelException { return 0; } public TemplateCollectionModel keys() throws TemplateModelException { return EMPTY_COLLECTION; } public TemplateCollectionModel values() throws TemplateModelException { return EMPTY_COLLECTION; } public TemplateModel get(String key) throws TemplateModelException { return null; } public boolean isEmpty() throws TemplateModelException { return true; } }; } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/UndeclaredThrowableException.java0000644000175000017500000000176711723544467032546 0ustar ebourgebourgpackage freemarker.template.utility; import java.io.PrintStream; import java.io.PrintWriter; /** * The equivalent of JDK 1.3 UndeclaredThrowableException. * @author Attila Szegedi * @version $Id: UndeclaredThrowableException.java,v 1.2 2003/09/17 13:30:05 szegedia Exp $ */ public class UndeclaredThrowableException extends RuntimeException { private final Throwable t; public UndeclaredThrowableException(Throwable t) { this.t = t; } public void printStackTrace() { printStackTrace(System.err); } public void printStackTrace(PrintStream ps) { synchronized (ps) { ps.print("Undeclared throwable:"); t.printStackTrace(ps); } } public void printStackTrace(PrintWriter pw) { synchronized (pw) { pw.print("Undeclared throwable:"); t.printStackTrace(pw); } } public Throwable getUndeclaredThrowable() { return t; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/utility/package.html0000644000175000017500000000052011723544471026344 0ustar ebourgebourg

Utility classes that may be used to customize aspects of FreeMarker. These implement the pluggable interfaces found in FreeMarker, including TemplateTransformModel and TemplateExceptionListener.

@author Nicholas Cull libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateScalarModel.java0000644000175000017500000000671211723544470027115 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * String values in a template data model must implement this interface. * (Actually, the name of this interface should be * TemplateStringModel. The bad name was inherited from the * ancient times, when there was only 1 kind of scalars in FreeMarker.) * * @version $Id: TemplateScalarModel.java,v 1.18 2004/11/28 12:58:33 ddekany Exp $ */ public interface TemplateScalarModel extends TemplateModel { /** * A constant value to use as the empty string. */ public TemplateModel EMPTY_STRING = new SimpleScalar(""); /** * Returns the string representation of this model. In general, avoid * returning null. In compatibility mode the engine will convert * null into empty string, however in normal mode it will * throw an exception if you return null from this method. */ public String getAsString() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateDirectiveBody.java0000644000175000017500000000203611723544471027457 0ustar ebourgebourgpackage freemarker.template; import java.io.IOException; import java.io.Writer; /** * Represents the body of a directive invocation. An implementation of this * class is passed to the {@link TemplateDirectiveModel#execute(freemarker.core.Environment, * java.util.Map, TemplateModel[], TemplateDirectiveBody)}. The implementation of the method is * free to invoke it any number of times, with any writer. * * @since 2.3.11 * @author Attila Szegedi * @version $Id: $ */ public interface TemplateDirectiveBody { /** * Renders the body of the directive body to the specified writer. The * writer is not flushed after the rendering. If you pass the environment's * writer, there is no need to flush it. If you supply your own writer, you * are responsible to flush/close it when you're done with using it (which * might be after multiple renderings). * @param out the writer to write the output to. */ public void render(Writer out) throws TemplateException, IOException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleCollection.java0000644000175000017500000001636111723544470026501 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.Serializable; import java.util.*; /** * A simple implementation of {@link TemplateCollectionModel}. * It's able to wrap java.util.Iterator-s and java.util.Collection-s. * If you wrap an Iterator, the variable can be <list>-ed (<forach>-ed) only once! * *

Consider using {@link SimpleSequence} instead of this class if you want to wrap Iterators. * SimpleSequence will read all elements of the Iterator, and store them in a List * (this may cause too high resource consumption in some applications), so you can list the variable * for unlimited times. Also, if you want to wrap Collections, and then list the resulting * variable for many times, SimpleSequence may gives better performance, as the * wrapping of non-TemplateModel objects happens only once. * *

This class is thread-safe. The returned TemplateModelIterator-s * are not thread-safe. * * @version $Id: SimpleCollection.java,v 1.13 2004/11/27 14:49:57 ddekany Exp $ */ public class SimpleCollection extends WrappingTemplateModel implements TemplateCollectionModel, Serializable { private boolean iteratorDirty; private Iterator iterator; private Collection collection; public SimpleCollection(Iterator iterator) { this.iterator = iterator; } public SimpleCollection(Collection collection) { this.collection = collection; } public SimpleCollection(Iterator iterator, ObjectWrapper wrapper) { super(wrapper); this.iterator = iterator; } public SimpleCollection(Collection collection, ObjectWrapper wrapper) { super(wrapper); this.collection = collection; } /** * Retrieves a template model iterator that is used to iterate over the elements in this collection. * *

When you wrap an Iterator and you get TemplateModelIterator for multiple times, * only on of the returned TemplateModelIterator instances can be really used. When you have called a * method of a TemplateModelIterator instance, all other instance will throw a * TemplateModelException when you try to call their methods, since the wrapped Iterator * can't return the first element. */ public TemplateModelIterator iterator() { if (iterator != null) { return new SimpleTemplateModelIterator(iterator, true); } else { synchronized (collection) { return new SimpleTemplateModelIterator(collection.iterator(), false); } } } /* * An instance of this class must be accessed only from a single thread. * The encapsulated Iterator may accessible from multiple threads (as multiple * SimpleTemplateModelIterator instance can wrap the same Iterator instance), * but the first thread which uses the shared Iterator will monopolize that. */ private class SimpleTemplateModelIterator implements TemplateModelIterator { private Iterator iterator; private boolean iteratorShared; SimpleTemplateModelIterator(Iterator iterator, boolean iteratorShared) { this.iterator = iterator; this.iteratorShared = iteratorShared; } public TemplateModel next() throws TemplateModelException { if (iteratorShared) makeIteratorDirty(); if (!iterator.hasNext()) { throw new TemplateModelException("The collection has no more elements."); } Object value = iterator.next(); if (value instanceof TemplateModel) { return (TemplateModel) value; } else { return wrap(value); } } public boolean hasNext() throws TemplateModelException { /* * Theorically this should not make the iterator dirty, * but I met sync. problems if I don't do it here. :( */ if (iteratorShared) makeIteratorDirty(); return iterator.hasNext(); } private void makeIteratorDirty() throws TemplateModelException { synchronized (SimpleCollection.this) { if (iteratorDirty) { throw new TemplateModelException( "This collection variable wraps a java.util.Iterator, " + "thus it can be -ed or -ed only once"); } else { iteratorDirty = true; iteratorShared = false; } } } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateMethodModelEx.java0000644000175000017500000001042211723544470027416 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.util.List; import freemarker.core.Environment; import freemarker.template.utility.DeepUnwrap; /** * A subinterface of {@link TemplateMethodModel} that acts on models, rather * than on strings. {@link TemplateMethodModel} interface will receive string * representations of its argument expressions, while this interface receives * the models themselves. The interface has no new methods. Instead, by * implementing this interface the class declares that it wishes to receive * actual TemplateModel instances in its arguments list when invoked instead of * their string representations. Further, if the implementation wishes to * operate on POJOs that might be underlying the models, it can use the static * utility methods in the {@link DeepUnwrap} class to easily obtain them. * @author Attila Szegedi, szegedia at users dot sourceforge dot net * @version $Id: TemplateMethodModelEx.java,v 1.8 2003/01/12 23:40:21 revusky Exp $ */ public interface TemplateMethodModelEx extends TemplateMethodModel { /** * Executes a method call. * @param arguments a List of {@link TemplateModel} objects * containing the values of the arguments passed to the method. If the * implementation wishes to operate on POJOs that might be underlying the * models, it can use the static utility methods in the {@link DeepUnwrap} * class to easily obtain them. * @return the return value of the method, or null. If the returned value * does not implement {@link TemplateModel}, it will be automatically * wrapped using the {@link Environment#getObjectWrapper() environment * object wrapper}. */ public Object exec(List arguments) throws TemplateModelException; }libfreemarker-java-2.3.19.orig/src/freemarker/template/AdapterTemplateModel.java0000644000175000017500000000330311723544472027263 0ustar ebourgebourgpackage freemarker.template; /** * Supplemental interface that can be implemented by classes that also implement * any of the {@link TemplateModel} interfaces. A class implementing this * interface usually serves as an adapter that provides bridging between a * different object model and FreeMarker template models. It provides a * capability to retrieve the underlying object. This interface is rarely * implemented by applications. It is tipically implemented by adapter classes * used for wrapping in various object wrapper implementation. * @author Attila Szegedi * @version $Id: AdapterTemplateModel.java,v 1.1 2005/06/12 19:03:07 szegedia Exp $ */ public interface AdapterTemplateModel extends TemplateModel { /** * Retrieves the underlying object, or some other object semantically * equivalent to its value narrowed by the class hint. * @param hint the desired class of the returned value. An implementation * should make reasonable effort to retrieve an object of the requested * class, but if that is impossible, it must at least return the underlying * object as-is. As a minimal requirement, an implementation must always * return the exact underlying object when * hint.isInstance(underlyingObject) == true holds. When called * with java.lang.Object.class, it should return a generic Java * object (i.e. if the model is wrapping a scripting lanugage object that is * further wrapping a Java object, the deepest underlying Java object should * be returned). * @return the underlying object, or its value accommodated for the hint * class. */ public Object getAdaptedObject(Class hint); } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleList.java0000644000175000017500000000570411723544472025322 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * This is a trivial subclass that exists for backward compatibility * with the SimpleList from FreeMarker Classic. * *

This class is thread-safe. * * @deprecated Use SimpleSequence instead. * @see SimpleSequence */ public class SimpleList extends SimpleSequence { public SimpleList() { } public SimpleList(java.util.List list) { super(list); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleNumber.java0000644000175000017500000000725311723544471025637 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.Serializable; /** * A simple implementation of the TemplateNumberModel * interface. Note that this class is immutable. * *

This class is thread-safe. * * @author Jonathan Revusky */ public final class SimpleNumber implements TemplateNumberModel, Serializable { /** * @serial the value of this SimpleNumber */ private Number value; public SimpleNumber(Number value) { this.value = value; } public SimpleNumber(byte val) { this.value = new Byte(val); } public SimpleNumber(short val) { this.value = new Short(val); } public SimpleNumber(int val) { this.value = new Integer(val); } public SimpleNumber(long val) { this.value = new Long(val); } public SimpleNumber(float val) { this.value = new Float(val); } public SimpleNumber(double val) { this.value = new Double(val); } public Number getAsNumber() { return value; } public String toString() { return value.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/LocalizedString.java0000644000175000017500000000201111723544470026314 0ustar ebourgebourgpackage freemarker.template; import freemarker.core.Environment; import java.util.Locale; /** * An abstract base class for scalars that vary by locale. * Here is a silly usage example. * * TemplateScalarModel localizedYes = new LocalizedString() { * public String getLocalizedString(java.util.Locale locale) { * String lang = locale.getLanguage(); * if "fr".equals(lang) * return "oui"; * else if "de".equals(lang) * return "sí"; * else * return "yes"; * } * }; * * @author Jonathan Revusky */ abstract public class LocalizedString implements TemplateScalarModel { public String getAsString() throws TemplateModelException { Environment env = Environment.getCurrentEnvironment(); Locale locale = env.getLocale(); return getLocalizedString(locale); } abstract public String getLocalizedString(Locale locale) throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateHashModel.java0000644000175000017500000000637511723544470026600 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * Hashes in a data model must implement this interface. Hashes * are FreeMarker data objects that contain other objects through key-value * mappings. * * @version $Id: TemplateHashModel.java,v 1.13 2005/06/08 02:13:34 revusky Exp $ */ public interface TemplateHashModel extends TemplateModel { /** * Gets a TemplateModel from the hash. * * @param key the name by which the TemplateModel * is identified in the template. * @return the TemplateModel referred to by the key, * or null if not found. */ TemplateModel get(String key) throws TemplateModelException; boolean isEmpty() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/Configuration.java0000644000175000017500000013374611723544467026060 0ustar ebourgebourg/* * Copyright (c) 2003-2006 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import freemarker.cache.CacheStorage; import freemarker.cache.ClassTemplateLoader; import freemarker.cache.FileTemplateLoader; import freemarker.cache.MruCacheStorage; import freemarker.cache.SoftCacheStorage; import freemarker.cache.TemplateCache; import freemarker.cache.TemplateLoader; import freemarker.core.Configurable; import freemarker.core.Environment; import freemarker.core.ParseException; import freemarker.template.utility.CaptureOutput; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.HtmlEscape; import freemarker.template.utility.NormalizeNewlines; import freemarker.template.utility.SecurityUtilities; import freemarker.template.utility.StandardCompress; import freemarker.template.utility.StringUtil; import freemarker.template.utility.XmlEscape; /** * Main entry point into the FreeMarker API, this class encapsulates the * various configuration parameters with which FreeMarker is run, as well * as serves as a central template loading and caching point. Note that * this class uses a default strategy for loading * and caching templates. You can plug in a replacement * template loading mechanism by using the {@link #setTemplateLoader(TemplateLoader)} * method. * *

This object is not synchronized. Thus, the settings must not be changed * after you have started to access the object from multiple threads. If you use multiple * threads, set everything directly after you have instantiated the Configuration * object, and don't change the settings anymore. * * @author Jonathan Revusky * @author Attila Szegedi * @version $Id: Configuration.java,v 1.122.2.5 2006/04/26 21:25:19 ddekany Exp $ */ public class Configuration extends Configurable implements Cloneable { public static final String DEFAULT_ENCODING_KEY = "default_encoding"; public static final String LOCALIZED_LOOKUP_KEY = "localized_lookup"; public static final String STRICT_SYNTAX_KEY = "strict_syntax"; public static final String WHITESPACE_STRIPPING_KEY = "whitespace_stripping"; public static final String CACHE_STORAGE_KEY = "cache_storage"; public static final String TEMPLATE_UPDATE_DELAY_KEY = "template_update_delay"; public static final String AUTO_IMPORT_KEY = "auto_import"; public static final String AUTO_INCLUDE_KEY = "auto_include"; public static final String TAG_SYNTAX_KEY = "tag_syntax"; public static final String INCOMPATIBLE_ENHANCEMENTS = "incompatible_enhancements"; public static final int AUTO_DETECT_TAG_SYNTAX = 0; public static final int ANGLE_BRACKET_TAG_SYNTAX = 1; public static final int SQUARE_BRACKET_TAG_SYNTAX = 2; public static final String DEFAULT_INCOMPATIBLE_ENHANCEMENTS = "2.3.0"; // [2.4] public static final int PARSED_DEFAULT_INCOMPATIBLE_ENHANCEMENTS = StringUtil.versionStringToInt(DEFAULT_INCOMPATIBLE_ENHANCEMENTS); private static Configuration defaultConfig = new Configuration(); private static String cachedVersion; private boolean strictSyntax = true, localizedLookup = true, whitespaceStripping = true; private String incompatibleEnhancements = DEFAULT_INCOMPATIBLE_ENHANCEMENTS; private int parsedIncompatibleEnhancements = PARSED_DEFAULT_INCOMPATIBLE_ENHANCEMENTS; private int tagSyntax = ANGLE_BRACKET_TAG_SYNTAX; private TemplateCache cache; private HashMap variables = new HashMap(); private HashMap encodingMap = new HashMap(); private Map autoImportMap = new HashMap(); private ArrayList autoImports = new ArrayList(), autoIncludes = new ArrayList(); private String defaultEncoding = SecurityUtilities.getSystemProperty("file.encoding"); public Configuration() { cache = new TemplateCache(); cache.setConfiguration(this); cache.setDelay(5000); loadBuiltInSharedVariables(); } public Object clone() { try { Configuration copy = (Configuration)super.clone(); copy.variables = new HashMap(variables); copy.encodingMap = new HashMap(encodingMap); copy.createTemplateCache(cache.getTemplateLoader(), cache.getCacheStorage()); return copy; } catch (CloneNotSupportedException e) { throw new RuntimeException("Clone is not supported, but it should be: " + e.getMessage()); } } private void loadBuiltInSharedVariables() { variables.put("capture_output", new CaptureOutput()); variables.put("compress", StandardCompress.INSTANCE); variables.put("html_escape", new HtmlEscape()); variables.put("normalize_newlines", new NormalizeNewlines()); variables.put("xml_escape", new XmlEscape()); } /** * Loads a preset language-to-encoding map. It assumes the usual character * encodings for most languages. * The previous content of the encoding map will be lost. * This default map currently contains the following mappings: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
arISO-8859-6
beISO-8859-5
bgISO-8859-5
caISO-8859-1
csISO-8859-2
daISO-8859-1
deISO-8859-1
elISO-8859-7
enISO-8859-1
esISO-8859-1
etISO-8859-1
fiISO-8859-1
frISO-8859-1
hrISO-8859-2
huISO-8859-2
isISO-8859-1
itISO-8859-1
iwISO-8859-8
jaShift_JIS
koEUC-KR
ltISO-8859-2
lvISO-8859-2
mkISO-8859-5
nlISO-8859-1
noISO-8859-1
plISO-8859-2
ptISO-8859-1
roISO-8859-2
ruISO-8859-5
shISO-8859-5
skISO-8859-2
slISO-8859-2
sqISO-8859-2
srISO-8859-5
svISO-8859-1
trISO-8859-9
ukISO-8859-5
zhGB2312
zh_TWBig5
* @see #clearEncodingMap * @see #setEncoding */ public void loadBuiltInEncodingMap() { encodingMap.clear(); encodingMap.put("ar", "ISO-8859-6"); encodingMap.put("be", "ISO-8859-5"); encodingMap.put("bg", "ISO-8859-5"); encodingMap.put("ca", "ISO-8859-1"); encodingMap.put("cs", "ISO-8859-2"); encodingMap.put("da", "ISO-8859-1"); encodingMap.put("de", "ISO-8859-1"); encodingMap.put("el", "ISO-8859-7"); encodingMap.put("en", "ISO-8859-1"); encodingMap.put("es", "ISO-8859-1"); encodingMap.put("et", "ISO-8859-1"); encodingMap.put("fi", "ISO-8859-1"); encodingMap.put("fr", "ISO-8859-1"); encodingMap.put("hr", "ISO-8859-2"); encodingMap.put("hu", "ISO-8859-2"); encodingMap.put("is", "ISO-8859-1"); encodingMap.put("it", "ISO-8859-1"); encodingMap.put("iw", "ISO-8859-8"); encodingMap.put("ja", "Shift_JIS"); encodingMap.put("ko", "EUC-KR"); encodingMap.put("lt", "ISO-8859-2"); encodingMap.put("lv", "ISO-8859-2"); encodingMap.put("mk", "ISO-8859-5"); encodingMap.put("nl", "ISO-8859-1"); encodingMap.put("no", "ISO-8859-1"); encodingMap.put("pl", "ISO-8859-2"); encodingMap.put("pt", "ISO-8859-1"); encodingMap.put("ro", "ISO-8859-2"); encodingMap.put("ru", "ISO-8859-5"); encodingMap.put("sh", "ISO-8859-5"); encodingMap.put("sk", "ISO-8859-2"); encodingMap.put("sl", "ISO-8859-2"); encodingMap.put("sq", "ISO-8859-2"); encodingMap.put("sr", "ISO-8859-5"); encodingMap.put("sv", "ISO-8859-1"); encodingMap.put("tr", "ISO-8859-9"); encodingMap.put("uk", "ISO-8859-5"); encodingMap.put("zh", "GB2312"); encodingMap.put("zh_TW", "Big5"); } /** * Clears language-to-encoding map. * @see #loadBuiltInEncodingMap * @see #setEncoding */ public void clearEncodingMap() { encodingMap.clear(); } /** * Returns the default (singleton) Configuration object. Note that you can * create as many separate configurations as you wish; this global instance * is provided for convenience, or when you have no reason to use a separate * instance. * * @deprecated The usage of the static singleton (the "default") * {@link Configuration} instance can easily cause erroneous, unpredictable * behavior. This is because multiple independent software components may use * FreeMarker internally inside the same application, so they will interfere * because of the common {@link Configuration} instance. Each such component * should use its own private {@link Configuration} object instead, that it * typically creates with new Configuration() when the component * is initialized. */ static public Configuration getDefaultConfiguration() { return defaultConfig; } /** * Sets the Configuration object that will be retrieved from future calls * to {@link #getDefaultConfiguration()}. * * @deprecated Using the "default" {@link Configuration} instance can * easily lead to erroneous, unpredictable behaviour. * See more {@link Configuration#getDefaultConfiguration() here...}. */ static public void setDefaultConfiguration(Configuration config) { defaultConfig = config; } /** * Sets a template loader that is used to look up and load templates. * By providing your own template loader, you can customize the way * templates are loaded. Several convenience methods in this class already * allow you to install commonly used loaders: * {@link #setClassForTemplateLoading(Class, String)}, * {@link #setDirectoryForTemplateLoading(File)}, and * {@link #setServletContextForTemplateLoading(Object, String)}. By default, * a multi-loader is used that first tries to load a template from the file * in the current directory, then from a resource on the classpath. */ public synchronized void setTemplateLoader(TemplateLoader loader) { createTemplateCache(loader, cache.getCacheStorage()); } private void createTemplateCache(TemplateLoader loader, CacheStorage storage) { TemplateCache oldCache = cache; cache = new TemplateCache(loader, storage); cache.setDelay(oldCache.getDelay()); cache.setConfiguration(this); cache.setLocalizedLookup(localizedLookup); } /** * @return the template loader that is used to look up and load templates. * @see #setTemplateLoader */ public TemplateLoader getTemplateLoader() { return cache.getTemplateLoader(); } /** * Sets the {@link CacheStorage} used for caching {@link Template}-s. The * default is a {@link SoftCacheStorage}. If the total size of the {@link Template} * objects is significant but most templates are used rarely, using a * {@link MruCacheStorage} instead might be advisable. If you don't want caching at * all, use {@link freemarker.cache.NullCacheStorage} (you can't use null). */ public synchronized void setCacheStorage(CacheStorage storage) { createTemplateCache(cache.getTemplateLoader(), storage); } /** * Set the explicit directory from which to load templates. */ public void setDirectoryForTemplateLoading(File dir) throws IOException { TemplateLoader tl = getTemplateLoader(); if (tl instanceof FileTemplateLoader) { String path = ((FileTemplateLoader) tl).baseDir.getCanonicalPath(); if (path.equals(dir.getCanonicalPath())) return; } setTemplateLoader(new FileTemplateLoader(dir)); } /** * Sets the servlet context from which to load templates * @param sctxt the ServletContext object. Note that the type is Object * to prevent class loading errors when user who uses FreeMarker not for * servlets has no javax.servlet in the CLASSPATH. * @param path the path relative to the ServletContext. * If this path is absolute, it is taken to be relative * to the server's URL, i.e. http://myserver.com/ * and if the path is relative, it is taken to be * relative to the web app context, i.e. * http://myserver.context.com/mywebappcontext/ */ public void setServletContextForTemplateLoading(Object sctxt, String path) { try { if (path == null) { setTemplateLoader( (TemplateLoader) ClassUtil.forName("freemarker.cache.WebappTemplateLoader") .getConstructor(new Class[]{ClassUtil.forName("javax.servlet.ServletContext")}) .newInstance(new Object[]{sctxt}) ); } else { setTemplateLoader( (TemplateLoader) ClassUtil.forName("freemarker.cache.WebappTemplateLoader") .getConstructor(new Class[]{ClassUtil.forName("javax.servlet.ServletContext"), String.class}) .newInstance(new Object[]{sctxt, path}) ); } } catch (Exception exc) { throw new RuntimeException("Internal FreeMarker error: " + exc); } } /** * Sets a class relative to which we do the * Class.getResource() call to load templates. */ public void setClassForTemplateLoading(Class clazz, String pathPrefix) { setTemplateLoader(new ClassTemplateLoader(clazz, pathPrefix)); } /** * Set the time in seconds that must elapse before checking whether there is a newer * version of a template file. * This method is thread-safe and can be called while the engine works. */ public void setTemplateUpdateDelay(int delay) { cache.setDelay(1000L * delay); } /** * Sets whether directives such as if, else, etcetera * must be written as #if, #else, etcetera. * Any tag not starting with <# or </# is considered as plain text * and will go to the output as is. Tag starting with <# or </# must * be valid FTL tag, or else the template is invalid (i.e. <#noSuchDirective> * is an error). */ public void setStrictSyntaxMode(boolean b) { strictSyntax = b; } /** * Tells whether directives such as if, else, etcetera * must be written as #if, #else, etcetera. * * @see #setStrictSyntaxMode */ public boolean getStrictSyntaxMode() { return strictSyntax; } /** * Sets which of the slightly non-backward compatible * bugfixes/enhancements should be enabled. The setting value is the * FreeMarker release version number where the enhancements * to enable were already present. The default is 2.3.0 in 2.3.x, 2.4.0 on * 2.4.x, and so on, thus by default compatibility with the latest x.y.0 * release is kept with new releases. If you develop a new application with, * for example, 2.3.25 and you need the non-backward compatible enhancements, * you should set this to 2.3.25. Thus if you later update FreeMarker to a * higher 2.3.x version, you will still only have the incompatible changes * that you have tested your application with. * *

This setting doesn't affect non-backward * compatible security fixes; they are always enabled. This setting also * doesn't affect enhancements where there's a significant chance of * breaking existing applications. * *

Using this setting is a good way of preparing for the next minor * (2nd) version number increase. When that happens, not only the default * value of this setting changes, but it's possible that older values become * unsupported. * *

Currently affected fixes/enhancements: *

    *
  • * 2.3.19: Bug fix: Wrong # tags were printed as static text instead of * causing parsing error if there was no correct # tag earlier in the * same template. *
  • *
* * @since 2.3.19 */ public void setIncompatibleEnhancements(String version) { parsedIncompatibleEnhancements = StringUtil.versionStringToInt(version); incompatibleEnhancements = version; } public String getIncompatibleEnhancements() { return incompatibleEnhancements; } /** * Same as {@link #getIncompatibleEnhancements()}, but returns the version * as an int, according to * {@link StringUtil#versionStringToInt(String)}. */ public int getParsedIncompatibleEnhancements() { return parsedIncompatibleEnhancements; } /** * Sets whether the FTL parser will try to remove * superfluous white-space around certain FTL tags. */ public void setWhitespaceStripping(boolean b) { whitespaceStripping = b; } /** * Gets whether the FTL parser will try to remove * superfluous white-space around certain FTL tags. * * @see #setWhitespaceStripping */ public boolean getWhitespaceStripping() { return whitespaceStripping; } /** * Determines the syntax of the template files (angle bracket VS square bracket) * that has no ftl directive in it. The tagSyntax * parameter must be one of: *
    *
  • {@link Configuration#AUTO_DETECT_TAG_SYNTAX}: * use the syntax of the first FreeMarker tag (can be anything, like list, * include, user defined, ...etc) *
  • {@link Configuration#ANGLE_BRACKET_TAG_SYNTAX}: * use the angle bracket syntax (the normal syntax) *
  • {@link Configuration#SQUARE_BRACKET_TAG_SYNTAX}: * use the square bracket syntax *
* *

In FreeMarker 2.3.x {@link Configuration#ANGLE_BRACKET_TAG_SYNTAX} is the * default for better backward compatibility. Starting from 2.4.x {@link * Configuration#AUTO_DETECT_TAG_SYNTAX} is the default, so it is recommended to use * that even for 2.3.x. * *

This setting is ignored for the templates that have ftl directive in * it. For those templates the syntax used for the ftl directive determines * the syntax. */ public void setTagSyntax(int tagSyntax) { if (tagSyntax != AUTO_DETECT_TAG_SYNTAX && tagSyntax != SQUARE_BRACKET_TAG_SYNTAX && tagSyntax != ANGLE_BRACKET_TAG_SYNTAX) { throw new IllegalArgumentException("This can only be set to one of three settings: Configuration.AUTO_DETECT_TAG_SYNTAX, Configuration.ANGLE_BRACKET_SYNTAX, or Configuration.SQAUARE_BRACKET_SYNTAX"); } this.tagSyntax = tagSyntax; } /** * See {@link #setTagSyntax(int)} to see the returned number. */ public int getTagSyntax() { return tagSyntax; } /** * Equivalent to getTemplate(name, thisCfg.getLocale(), thisCfg.getEncoding(thisCfg.getLocale()), true). */ public Template getTemplate(String name) throws IOException { Locale loc = getLocale(); return getTemplate(name, loc, getEncoding(loc), true); } /** * Equivalent to getTemplate(name, locale, thisCfg.getEncoding(locale), true). */ public Template getTemplate(String name, Locale locale) throws IOException { return getTemplate(name, locale, getEncoding(locale), true); } /** * Equivalent to getTemplate(name, thisCfg.getLocale(), encoding, true). */ public Template getTemplate(String name, String encoding) throws IOException { return getTemplate(name, getLocale(), encoding, true); } /** * Equivalent to getTemplate(name, locale, encoding, true). */ public Template getTemplate(String name, Locale locale, String encoding) throws IOException { return getTemplate(name, locale, encoding, true); } /** * Retrieves a template specified by a name and locale, interpreted using * the specified character encoding, either parsed or unparsed. For the * exact semantics of parameters, see * {@link TemplateCache#getTemplate(String, Locale, String, boolean)}. * @return the requested template. * @throws FileNotFoundException if the template could not be found. * @throws IOException if there was a problem loading the template. * @throws ParseException (extends IOException) if the template is syntactically bad. */ public Template getTemplate(String name, Locale locale, String encoding, boolean parse) throws IOException { Template result = cache.getTemplate(name, locale, encoding, parse); if (result == null) { throw new FileNotFoundException("Template " + name + " not found."); } return result; } /** * Sets the default encoding for converting bytes to characters when * reading template files in a locale for which no explicit encoding * was specified. Defaults to default system encoding. */ public void setDefaultEncoding(String encoding) { defaultEncoding = encoding; } /** * Gets the default encoding for converting bytes to characters when * reading template files in a locale for which no explicit encoding * was specified. Defaults to default system encoding. */ public String getDefaultEncoding() { return defaultEncoding; } /** * Gets the preferred character encoding for the given locale, or the * default encoding if no encoding is set explicitly for the specified * locale. You can associate encodings with locales using * {@link #setEncoding(Locale, String)} or {@link #loadBuiltInEncodingMap()}. * @param loc the locale * @return the preferred character encoding for the locale. */ public String getEncoding(Locale loc) { // Try for a full name match (may include country and variant) String charset = (String) encodingMap.get(loc.toString()); if (charset == null) { if (loc.getVariant().length() > 0) { Locale l = new Locale(loc.getLanguage(), loc.getCountry()); charset = (String) encodingMap.get(l.toString()); if (charset != null) { encodingMap.put(loc.toString(), charset); } } charset = (String) encodingMap.get(loc.getLanguage()); if (charset != null) { encodingMap.put(loc.toString(), charset); } } return charset != null ? charset : defaultEncoding; } /** * Sets the character set encoding to use for templates of * a given locale. If there is no explicit encoding set for some * locale, then the default encoding will be used, what you can * set with {@link #setDefaultEncoding}. * * @see #clearEncodingMap * @see #loadBuiltInEncodingMap */ public void setEncoding(Locale locale, String encoding) { encodingMap.put(locale.toString(), encoding); } /** * Adds a shared variable to the configuration. * Shared variables are variables that are visible * as top-level variables for all templates which use this * configuration, if the data model does not contain a * variable with the same name. * *

Never use TemplateModel implementation that is not thread-safe for shared variables, * if the configuration is used by multiple threads! It is the typical situation for Servlet based Web sites. * * @param name the name used to access the data object from your template. * If a shared variable with this name already exists, it will replace * that. * @see #setSharedVariable(String,Object) * @see #setAllSharedVariables */ public void setSharedVariable(String name, TemplateModel tm) { variables.put(name, tm); } /** * Returns the set containing the names of all defined shared variables. * The method returns a new Set object on each call that is completely * disconnected from the Configuration. That is, modifying the set will have * no effect on the Configuration object. */ public Set getSharedVariableNames() { return new HashSet(variables.keySet()); } /** * Adds shared variable to the configuration. * It uses {@link Configurable#getObjectWrapper()} to wrap the * obj. * @see #setSharedVariable(String,TemplateModel) * @see #setAllSharedVariables */ public void setSharedVariable(String name, Object obj) throws TemplateModelException { setSharedVariable(name, getObjectWrapper().wrap(obj)); } /** * Adds all object in the hash as shared variable to the configuration. * *

Never use TemplateModel implementation that is not thread-safe for shared variables, * if the configuration is used by multiple threads! It is the typical situation for Servlet based Web sites. * * @param hash a hash model whose objects will be copied to the * configuration with same names as they are given in the hash. * If a shared variable with these names already exist, it will be replaced * with those from the map. * * @see #setSharedVariable(String,Object) * @see #setSharedVariable(String,TemplateModel) */ public void setAllSharedVariables(TemplateHashModelEx hash) throws TemplateModelException { TemplateModelIterator keys = hash.keys().iterator(); TemplateModelIterator values = hash.values().iterator(); while(keys.hasNext()) { setSharedVariable(((TemplateScalarModel)keys.next()).getAsString(), values.next()); } } /** * Gets a shared variable. Shared variables are variables that are * available to all templates. When a template is processed, and an identifier * is undefined in the data model, a shared variable object with the same identifier * is then looked up in the configuration. There are several predefined variables * that are always available through this method, see the FreeMarker manual * for a comprehensive list of them. * * @see #setSharedVariable(String,Object) * @see #setSharedVariable(String,TemplateModel) * @see #setAllSharedVariables */ public TemplateModel getSharedVariable(String name) { return (TemplateModel) variables.get(name); } /** * Removes all shared variables, except the predefined ones (compress, html_escape, etc.). */ public void clearSharedVariables() { variables.clear(); loadBuiltInSharedVariables(); } /** * Removes all entries from the template cache, thus forcing reloading of templates * on subsequent getTemplate calls. * This method is thread-safe and can be called while the engine works. */ public void clearTemplateCache() { cache.clear(); } /** * Equivalent to removeTemplateFromCache(name, thisCfg.getLocale(), thisCfg.getEncoding(thisCfg.getLocale()), true). */ public void removeTemplateFromCache(String name) throws IOException { Locale loc = getLocale(); removeTemplateFromCache(name, loc, getEncoding(loc), true); } /** * Equivalent to removeTemplateFromCache(name, locale, thisCfg.getEncoding(locale), true). */ public void removeTemplateFromCache(String name, Locale locale) throws IOException { removeTemplateFromCache(name, locale, getEncoding(locale), true); } /** * Equivalent to removeTemplateFromCache(name, thisCfg.getLocale(), encoding, true). */ public void removeTemplateFromCache(String name, String encoding) throws IOException { removeTemplateFromCache(name, getLocale(), encoding, true); } /** * Equivalent to removeTemplateFromCache(name, locale, encoding, true). */ public void removeTemplateFromCache(String name, Locale locale, String encoding) throws IOException { removeTemplateFromCache(name, locale, encoding, true); } /** * Removes a template from the template cache, hence forcing the re-loading * of it when it's next time requested. This is to give the application * finer control over cache updating than {@link #setTemplateUpdateDelay(int)} * alone does. * * For the meaning of the parameters, see * {@link #getTemplate(String, Locale, String, boolean)}. */ public void removeTemplateFromCache( String name, Locale locale, String encoding, boolean parse) throws IOException { cache.removeTemplate(name, locale, encoding, parse); } /** * Returns if localized template lookup is enabled or not. * This method is thread-safe and can be called while the engine works. */ public boolean getLocalizedLookup() { return cache.getLocalizedLookup(); } /** * Enables/disables localized template lookup. Enabled by default. * This method is thread-safe and can be called while the engine works. */ public void setLocalizedLookup(boolean localizedLookup) { this.localizedLookup = localizedLookup; cache.setLocalizedLookup(localizedLookup); } /** * Sets a setting by name and string value. * * In additional to the settings understood by * {@link Configurable#setSetting the super method}, it understands these: *

    *
  • "auto_import": Sets the list of auto-imports. Example of valid value: *
    /lib/form.ftl as f, /lib/widget as w, "/lib/evil name.ftl" as odd * See: {@link #setAutoImports} *
  • "auto_include": Sets the list of auto-includes. Example of valid value: *
    /include/common.ftl, "/include/evil name.ftl" * See: {@link #setAutoIncludes} *
  • "default_encoding": The name of the charset, such as "UTF-8". * See: {@link #setDefaultEncoding} *
  • "localized_lookup": * "true", "false", "yes", "no", * "t", "f", "y", "n". * Case insensitive. * See: {@link #setLocalizedLookup} *
  • "strict_syntax": "true", "false", etc. * See: {@link #setStrictSyntaxMode} *
  • "whitespace_stripping": "true", "false", etc. * See: {@link #setWhitespaceStripping} *
  • "cache_storage": If the value contains dot, then it is * interpreted as class name, and the object will be created with * its parameterless constructor. If the value does not contain dot, * then a {@link freemarker.cache.MruCacheStorage} will be used with the * maximum strong and soft sizes specified with the setting value. Examples * of valid setting values: * *
    Setting valuemax. strong sizemax. soft size *
    "strong:50, soft:500"50500 *
    "strong:100, soft"100Integer.MAX_VALUE *
    "strong:100"1000 *
    "soft:100"0100 *
    "strong"Integer.MAX_VALUE0 *
    "soft"0Integer.MAX_VALUE *
    * The value is not case sensitive. The order of soft and strong * entries is not significant. * For more details see: {@link #setCacheStorage} *
  • "template_update_delay": Valid positive integer, the * update delay measured in seconds. * See: {@link #setTemplateUpdateDelay} *
  • "tag_syntax": Must be one of: * "auto_detect", "angle_bracket", * "square_bracket". *
  • "incompatible_enhancements": The FreeMarker version * number where the desired enhancements were already implemented. * See: {@link #setIncompatibleEnhancements(String)}. *
* * @param key the name of the setting. * @param value the string that describes the new value of the setting. * * @throws UnknownSettingException if the key is wrong. * @throws TemplateException if the new value of the setting can't be set * for any other reasons. */ public void setSetting(String key, String value) throws TemplateException { if ("TemplateUpdateInterval".equalsIgnoreCase(key)) { key = TEMPLATE_UPDATE_DELAY_KEY; } else if ("DefaultEncoding".equalsIgnoreCase(key)) { key = DEFAULT_ENCODING_KEY; } boolean callSuper = false; try { if (DEFAULT_ENCODING_KEY.equals(key)) { setDefaultEncoding(value); } else if (LOCALIZED_LOOKUP_KEY.equals(key)) { setLocalizedLookup(StringUtil.getYesNo(value)); } else if (STRICT_SYNTAX_KEY.equals(key)) { setStrictSyntaxMode(StringUtil.getYesNo(value)); } else if (WHITESPACE_STRIPPING_KEY.equals(key)) { setWhitespaceStripping(StringUtil.getYesNo(value)); } else if (CACHE_STORAGE_KEY.equals(key)) { if (value.indexOf('.') == -1) { int strongSize = 0; int softSize = 0; Map map = StringUtil.parseNameValuePairList( value, String.valueOf(Integer.MAX_VALUE)); Iterator it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry ent = (Map.Entry) it.next(); String pname = (String) ent.getKey(); int pvalue; try { pvalue = Integer.parseInt((String) ent.getValue()); } catch (NumberFormatException e) { throw invalidSettingValueException(key, value); } if ("soft".equalsIgnoreCase(pname)) { softSize = pvalue; } else if ("strong".equalsIgnoreCase(pname)) { strongSize = pvalue; } else { throw invalidSettingValueException(key, value); } } if (softSize == 0 && strongSize == 0) { throw invalidSettingValueException(key, value); } setCacheStorage(new MruCacheStorage(strongSize, softSize)); } else { setCacheStorage((CacheStorage) ClassUtil.forName(value) .newInstance()); } } else if (TEMPLATE_UPDATE_DELAY_KEY.equals(key)) { setTemplateUpdateDelay(Integer.parseInt(value)); } else if (AUTO_INCLUDE_KEY.equals(key)) { setAutoIncludes(parseAsList(value)); } else if (AUTO_IMPORT_KEY.equals(key)) { setAutoImports(parseAsImportList(value)); } else if (TAG_SYNTAX_KEY.equals(key)) { if ("auto_detect".equals(value)) { setTagSyntax(AUTO_DETECT_TAG_SYNTAX); } else if ("angle_bracket".equals(value)) { setTagSyntax(ANGLE_BRACKET_TAG_SYNTAX); } else if ("square_bracket".equals(value)) { setTagSyntax(SQUARE_BRACKET_TAG_SYNTAX); } else { throw invalidSettingValueException(key, value); } } else if (INCOMPATIBLE_ENHANCEMENTS.equals(key)) { setIncompatibleEnhancements(value); } else { callSuper = true; } } catch(Exception e) { throw new TemplateException( "Failed to set setting " + StringUtil.jQuote(key) + " to value " + StringUtil.jQuote(value) + "; see cause exception.", e, getEnvironment()); } if (callSuper) { super.setSetting(key, value); } } /** * Add an auto-imported template. * The importing will happen at the top of any template that * is vended by this Configuration object. * @param namespace the name of the namespace into which the template is imported * @param template the name of the template */ public synchronized void addAutoImport(String namespace, String template) { autoImports.remove(namespace); autoImports.add(namespace); autoImportMap.put(namespace, template); } /** * Remove an auto-imported template * @param namespace the name of the namespace into which the template was imported */ public synchronized void removeAutoImport(String namespace) { autoImports.remove(namespace); autoImportMap.remove(namespace); } /** * set a map of namespace names to templates for auto-importing * a set of templates. Note that all previous auto-imports are removed. */ public synchronized void setAutoImports(Map map) { autoImports = new ArrayList(map.keySet()); if (map instanceof HashMap) { autoImportMap = (Map) ((HashMap) map).clone(); } else if (map instanceof SortedMap) { autoImportMap = new TreeMap(map); } else { autoImportMap = new HashMap(map); } } protected void doAutoImportsAndIncludes(Environment env) throws TemplateException, IOException { for (int i=0; i"2.2.5", "2.3pre13", * "2.3pre13mod", "2.3rc1", "2.3", * "3.0". * *

Notes on FreeMarker version numbering rules: *

    *
  • "pre" and "rc" (lowercase!) means "preview" and "release * candidate" respectively. It is must be followed with a * number (as "1" for the first release candidate). *
  • The "mod" after the version number indicates that it's an * unreleased modified version of the released version. * After releases, the nighly builds are such releases. E.g. * the nightly build after releasing "2.2.1" but before releasing * "2.2.2" is "2.2.1mod". *
  • The 2nd version number must be present, and maybe 0, * as in "3.0". *
  • The 3rd version number is never 0. E.g. the version * number string for the first release of the 2.2 series * is "2.2", and NOT "2.2.0". *
  • When only the 3rd version number increases * (2.2 -> 2.2.1, 2.2.1 -> 2.2.2 etc.), 100% backward compatiblity * with the previous version MUST be kept. * This means that freemarker.jar can be replaced in an * application without risk (as far as the application doesn't depend * on the presence of a FreeMarker bug). * Note that backward compatibility restrictions do not apply for * preview releases. *
*/ public static String getVersionNumber() { if (cachedVersion != null) { return cachedVersion; } try { Properties vp = new Properties(); InputStream ins = Configuration.class.getClassLoader() .getResourceAsStream("freemarker/version.properties"); if (ins == null) { throw new RuntimeException("Version file is missing."); } else { try { vp.load(ins); } finally { ins.close(); } String v = vp.getProperty("version"); if (v == null) { throw new RuntimeException("Version file is corrupt: version key is missing."); } cachedVersion = v; } return cachedVersion; } catch (IOException e) { throw new RuntimeException("Failed to load version file: " + e); } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleScalar.java0000644000175000017500000000671511723544470025615 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.Serializable; /** * A simple implementation of the TemplateScalarModel * interface, using a String. * As of version 2.0 this object is immutable. * *

This class is thread-safe. * * @version $Id: SimpleScalar.java,v 1.38 2004/09/10 20:50:45 ddekany Exp $ * @see SimpleSequence * @see SimpleHash */ public final class SimpleScalar implements TemplateScalarModel, Serializable { /** * @serial the value of this SimpleScalar if it wraps a * String. */ private String value; /** * Constructs a SimpleScalar containing a string value. * @param value the string value. */ public SimpleScalar(String value) { this.value = value; } public String getAsString() { return (value == null) ? "" : value; } public String toString() { return value; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateModelListSequence.java0000644000175000017500000000655711723544470030323 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.util.List; import freemarker.template.TemplateModel; import freemarker.template.TemplateSequenceModel; /** * Sequence that wraps a java.util.List of already wrapped objects * directly, with minimal resource usage. Warning! It does not copy the original * list. * * @author Daniel Dekany * @version $Id: TemplateModelListSequence.java,v 1.2 2004/01/06 17:06:43 szegedia Exp $ */ public class TemplateModelListSequence implements TemplateSequenceModel { private List list; public TemplateModelListSequence(List list) { this.list = list; } public TemplateModel get(int index) { return (TemplateModel) list.get(index); } public int size() { return list.size(); } public Object getWrappedObject() { return list; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/WrappingTemplateModel.java0000644000175000017500000001313311723544467027500 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * A base class for containers that wrap arbitrary Java objects into * {@link TemplateModel} instances. * * @version $Id: WrappingTemplateModel.java,v 1.18.2.1 2005/12/07 00:41:23 revusky Exp $ */ abstract public class WrappingTemplateModel { private static ObjectWrapper defaultObjectWrapper = DefaultObjectWrapper.instance; private ObjectWrapper objectWrapper; /** * Sets the default object wrapper that is used when a wrapping template * model is constructed without being passed an explicit object wrapper. * The default value is {@link ObjectWrapper#SIMPLE_WRAPPER}. * Note that {@link Configuration#setSharedVariable(String, Object)} and * {@link Template#process(Object, java.io.Writer)} don't use this setting, * they rather use whatever object wrapper their * {@link Configuration#getObjectWrapper()} method returns. */ public static void setDefaultObjectWrapper(ObjectWrapper objectWrapper) { defaultObjectWrapper = objectWrapper; } /** * Returns the default object wrapper that is used when a wrapping template * model is constructed without being passed an explicit object wrapper. * Note that {@link Configuration#setSharedVariable(String, Object)} and * {@link Template#process(Object, java.io.Writer)} don't use this setting, * they rather use whatever object wrapper their * {@link Configuration#getObjectWrapper()} method returns. */ public static ObjectWrapper getDefaultObjectWrapper() { return defaultObjectWrapper; } /** * Protected constructor that creates a new wrapping template model using * the default object wrapper. */ protected WrappingTemplateModel() { this(defaultObjectWrapper); } /** * Protected constructor that creates a new wrapping template model using * the specified object wrapper. * @param objectWrapper the wrapper to use. If null is passed, the default * object wrapper is used. */ protected WrappingTemplateModel(ObjectWrapper objectWrapper) { this.objectWrapper = objectWrapper != null ? objectWrapper : defaultObjectWrapper; if (this.objectWrapper == null) { this.objectWrapper = defaultObjectWrapper = new DefaultObjectWrapper(); } } /** * Returns the object wrapper instance used by this wrapping template model. */ public ObjectWrapper getObjectWrapper() { return objectWrapper; } public void setObjectWrapper(ObjectWrapper objectWrapper) { this.objectWrapper = objectWrapper; } /** * Wraps the passed object into a template model using this object's object * wrapper. * @param obj the object to wrap * @return the template model that wraps the object * @throws TemplateModelException if the wrapper does not know how to * wrap the passed object. */ protected final TemplateModel wrap(Object obj) throws TemplateModelException { return objectWrapper.wrap(obj); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateSequenceModel.java0000644000175000017500000000765011723544470027462 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * List values in a template data model whose elements are accessed by the * index operator should implement this interface. In addition to * accessing elements by index and querying size using the ?size * built-in, objects that implement this interface can be iterated in * <#foreach ...> and <#list ...> directives. The * iteration is implemented by calling the {@link #get(int)} method * repeatedly starting from zero and going to {@link #size()} - 1. * @author Attila Szegedi, szegedia at users dot sourceforge dot net * @version $Id: TemplateSequenceModel.java,v 1.10 2004/11/27 14:49:57 ddekany Exp $ */ public interface TemplateSequenceModel extends TemplateModel { /** * Retrieves the i-th template model in this sequence. * * @return the item at the specified index, or null if * the index is out of bounds. Note that a null value is * interpreted by FreeMarker as "variable does not exist", and accessing * a missing variables is usually considered as an error in the FreeMarker * Template Language, so the usage of a bad index will not remain hidden. */ TemplateModel get(int index) throws TemplateModelException; /** * @return the number of items in the list. */ int size() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateModelException.java0000644000175000017500000001021611723544467027646 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import freemarker.core.Environment; /** * Template model implementation classes should throw this exception if * requested data cannot be retrieved. * * @version $Id: TemplateModelException.java,v 1.14 2003/04/22 21:03:22 revusky Exp $ */ public class TemplateModelException extends TemplateException { /** * Constructs a TemplateModelException with no * specified detail message. */ public TemplateModelException() { this(null, null); } /** * Constructs a TemplateModelException with the * specified detail message. * * @param description the detail message. */ public TemplateModelException(String description) { this(description, null); } /** * Constructs a TemplateModelException with the given underlying * Exception, but no detail message. * * @param cause the underlying Exception that caused this * exception to be raised */ public TemplateModelException(Exception cause) { this(null, cause); } /** * Constructs a TemplateModelException with both a description of the error * that occurred and the underlying Exception that caused this exception * to be raised. * * @param description the description of the error that occurred * @param cause the underlying Exception that caused this * exception to be raised */ public TemplateModelException(String description, Exception cause) { super( description, cause, Environment.getCurrentEnvironment() ); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleSequence.java0000644000175000017500000002443711723544470026161 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import freemarker.ext.beans.BeansWrapper; /** *

A convenient implementation of a list. This * object implements {@link TemplateSequenceModel}, using an underlying * java.util.List implementation.

* *

A SimpleSequence can act as a cache for a * TemplateCollectionModel, e.g. one that gets data from a * database. When passed a TemplateCollectionModel as an * argument to its constructor, the SimpleSequence immediately * copies all the elements and discards the TemplateCollectionModel.

* *

This class is thread-safe if you don't call the add method after you * have made the object available for multiple threads. * *

Note:
* As of 2.0, this class is unsynchronized by default. * To obtain a synchronized wrapper, call the {@link #synchronizedWrapper} method.

* * @version $Id: SimpleSequence.java,v 1.53 2005/06/21 18:17:54 ddekany Exp $ * @see SimpleHash * @see SimpleScalar */ public class SimpleSequence extends WrappingTemplateModel implements TemplateSequenceModel, Serializable { /** * @serial The List that this SimpleSequence wraps. */ protected final List list; private List unwrappedList; /** * Constructs an empty simple sequence that will use the the default object * wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}. */ public SimpleSequence() { this((ObjectWrapper) null); } /** * Constructs an empty simple sequence with preallocated capacity and using * the default object wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}. */ public SimpleSequence(int capacity) { list = new ArrayList(capacity); } /** * Constructs a simple sequence that will contain the elements * from the specified {@link Collection} and will use the the default * object wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}. * @param collection the collection containing initial values. Note that a * copy of the collection is made for internal use. */ public SimpleSequence(Collection collection) { this(collection, null); } /** * Constructs a simple sequence from the passed collection model using the * default object wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}. */ public SimpleSequence(TemplateCollectionModel tcm) throws TemplateModelException { ArrayList alist = new ArrayList(); for (TemplateModelIterator it = tcm.iterator(); it.hasNext();) { alist.add(it.next()); } alist.trimToSize(); list = alist; } /** * Constructs an empty simple sequence using the specified object wrapper. * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)} is * used. */ public SimpleSequence(ObjectWrapper wrapper) { super(wrapper); list = new ArrayList(); } /** * Constructs a simple sequence that will contain the elements * from the specified {@link Collection} and will use the specified object * wrapper. * @param collection the collection containing initial values. Note that a * copy of the collection is made for internal use. * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)} is * used. */ public SimpleSequence(Collection collection, ObjectWrapper wrapper) { super(wrapper); list = new ArrayList(collection); } /** * Adds an arbitrary object to the end of this SimpleSequence. * If the object itself does not implement the {@link TemplateModel} * interface, it will be wrapped into an appropriate adapter on the first * call to {@link #get(int)}. * * @param obj the boolean to be added. */ public void add(Object obj) { list.add(obj); unwrappedList = null; } /** * Adds a boolean to the end of this SimpleSequence, by * coercing the boolean into {@link TemplateBooleanModel#TRUE} or * {@link TemplateBooleanModel#FALSE}. * * @param b the boolean to be added. */ public void add(boolean b) { if (b) { add(TemplateBooleanModel.TRUE); } else { add(TemplateBooleanModel.FALSE); } } /** * Note that this method creates and returns a deep-copy of the underlying list used * internally. This could be a gotcha for some people * at some point who want to alter something in the data model, * but we should maintain our immutability semantics (at least using default SimpleXXX wrappers) * for the data model. It will recursively unwrap the stuff in the underlying container. */ public List toList() throws TemplateModelException { if (unwrappedList == null) { Class listClass = list.getClass(); List result = null; try { result = (List) listClass.newInstance(); } catch (Exception e) { throw new TemplateModelException("Error instantiating an object of type " + listClass.getName() + "\n" + e.getMessage()); } BeansWrapper bw = BeansWrapper.getDefaultInstance(); for (int i=0; iA core FreeMarker API that represents a compiled template. * Typically, you will use a {@link Configuration} object to instantiate a template. * *
      Configuration cfg = new Configuration();
      ...
      Template myTemplate = cfg.getTemplate("myTemplate.html");
   
* *

However, you can also construct a template directly by passing in to * the appropriate constructor a java.io.Reader instance that is set to * read the raw template text. The compiled template is * stored in an an efficient data structure for later use. * *

To render the template, i.e. to merge it with a data model, and * thus produce "cooked" output, call the process method. * *

Any error messages from exceptions thrown during compilation will be * included in the output stream and thrown back to the calling code. * To change this behavior, you can install custom exception handlers using * {@link Configurable#setTemplateExceptionHandler(TemplateExceptionHandler)} on * a Configuration object (for all templates belonging to a configuration) or on * a Template object (for a single template). * *

It's not legal to modify the values of FreeMarker settings: a) while the * template is executing; b) if the template object is already accessible from * multiple threads. * * @version $Id: Template.java,v 1.216.2.3 2006/03/10 17:49:02 revusky Exp $ */ public class Template extends Configurable { public static final String DEFAULT_NAMESPACE_PREFIX = "D"; public static final String NO_NS_PREFIX = "N"; private Map macros = new HashMap(); private List imports = new Vector(); private TemplateElement rootElement; private String encoding, defaultNS; private final String name; private final ArrayList lines = new ArrayList(); private Map prefixToNamespaceURILookup = new HashMap(); private Map namespaceURIToPrefixLookup = new HashMap(); /** * A prime constructor to which all other constructors should * delegate directly or indirectly. */ private Template(String name, Configuration cfg) { super(cfg != null ? cfg : Configuration.getDefaultConfiguration()); this.name = name; } /** * Constructs a template from a character stream. * * @param name the path of the template file relative to the directory what you use to store * the templates. See {@link #getName} for more details. * @param reader the character stream to read from. It will always be closed (Reader.close()). * @param cfg the Configuration object that this Template is associated with. * If this is null, the "default" {@link Configuration} object is used, * which is highly discouraged, because it can easily lead to * erroneous, unpredictable behaviour. * (See more {@link Configuration#getDefaultConfiguration() here...}) * @param encoding This is the encoding that we are supposed to be using. If this is * non-null (It's not actually necessary because we are using a Reader) then it is * checked against the encoding specified in the FTL header -- assuming that is specified, * and if they don't match a WrongEncodingException is thrown. */ public Template(String name, Reader reader, Configuration cfg, String encoding) throws IOException { this(name, cfg); this.encoding = encoding; if (!(reader instanceof BufferedReader)) { reader = new BufferedReader(reader, 0x1000); } LineTableBuilder ltb = new LineTableBuilder(reader); try { try { FMParser parser = new FMParser(this, ltb, getConfiguration().getStrictSyntaxMode(), getConfiguration().getWhitespaceStripping(), getConfiguration().getTagSyntax(), getConfiguration().getParsedIncompatibleEnhancements()); this.rootElement = parser.Root(); } catch (TokenMgrError exc) { throw new ParseException("Token manager error: " + exc, 0, 0); } } catch(ParseException e) { e.setTemplateName(name); throw e; } finally { ltb.close(); } DebuggerService.registerTemplate(this); namespaceURIToPrefixLookup = Collections.unmodifiableMap(namespaceURIToPrefixLookup); prefixToNamespaceURILookup = Collections.unmodifiableMap(prefixToNamespaceURILookup); } /** * This is equivalent to Template(name, reader, cfg, null) */ public Template(String name, Reader reader, Configuration cfg) throws IOException { this(name, reader, cfg, null); } /** * Constructs a template from a character stream. * * This is the same as the 3 parameter version when you pass null * as the cfg parameter. * * @deprecated This constructor uses the "default" {@link Configuration} * instance, which can easily lead to erroneous, unpredictable behaviour. * See more {@link Configuration#getDefaultConfiguration() here...}. */ public Template(String name, Reader reader) throws IOException { this(name, reader, null); } /** * This constructor is only used internally. */ Template(String name, TemplateElement root, Configuration config) { this(name, config); this.rootElement = root; DebuggerService.registerTemplate(this); } /** * Returns a trivial template, one that is just a single block of * plain text, no dynamic content. (Used by the cache module to create * unparsed templates.) * @param name the path of the template file relative to the directory what you use to store * the templates. See {@link #getName} for more details. * @param content the block of text that this template represents * @param config the configuration to which this template belongs */ static public Template getPlainTextTemplate(String name, String content, Configuration config) { Template template = new Template(name, config); TextBlock block = new TextBlock(content); template.rootElement = block; DebuggerService.registerTemplate(template); return template; } /** * Processes the template, using data from the map, and outputs * the resulting text to the supplied Writer The elements of the * map are converted to template models using the default object wrapper * returned by the {@link Configuration#getObjectWrapper() getObjectWrapper()} * method of the Configuration. * @param rootMap the root node of the data model. If null, an * empty data model is used. Can be any object that the effective object * wrapper can turn into a TemplateHashModel. Basically, simple and * beans wrapper can turn java.util.Map objects into hashes * and the Jython wrapper can turn both a PyDictionary as well as * any object that implements __getitem__ into a template hash. * Naturally, you can pass any object directly implementing * TemplateHashModel as well. * @param out a Writer to output the text to. * @throws TemplateException if an exception occurs during template processing * @throws IOException if an I/O exception occurs during writing to the writer. */ public void process(Object rootMap, Writer out) throws TemplateException, IOException { createProcessingEnvironment(rootMap, out, null).process(); } /** * Processes the template, using data from the root map object, and outputs * the resulting text to the supplied writer, using the supplied * object wrapper to convert map elements to template models. * @param rootMap the root node of the data model. If null, an * empty data model is used. Can be any object that the effective object * wrapper can turn into a TemplateHashModel Basically, simple and * beans wrapper can turn java.util.Map objects into hashes * and the Jython wrapper can turn both a PyDictionary as well as any * object that implements __getitem__ into a template hash. * Naturally, you can pass any object directly implementing * TemplateHashModel as well. * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper retrieved * by {@link Configurable#getObjectWrapper()} is used. * @param out the writer to output the text to. * @param rootNode The root node for recursive processing, this may be null. * * @throws TemplateException if an exception occurs during template processing * @throws IOException if an I/O exception occurs during writing to the writer. */ public void process(Object rootMap, Writer out, ObjectWrapper wrapper, TemplateNodeModel rootNode) throws TemplateException, IOException { Environment env = createProcessingEnvironment(rootMap, out, wrapper); if (rootNode != null) { env.setCurrentVisitorNode(rootNode); } env.process(); } /** * Processes the template, using data from the root map object, and outputs * the resulting text to the supplied writer, using the supplied * object wrapper to convert map elements to template models. * @param rootMap the root node of the data model. If null, an * empty data model is used. Can be any object that the effective object * wrapper can turn into a TemplateHashModel Basically, simple and * beans wrapper can turn java.util.Map objects into hashes * and the Jython wrapper can turn both a PyDictionary as well as any * object that implements __getitem__ into a template hash. * Naturally, you can pass any object directly implementing * TemplateHashModel as well. * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper retrieved * by {@link Configurable#getObjectWrapper()} is used. * @param out the writer to output the text to. * * @throws TemplateException if an exception occurs during template processing * @throws IOException if an I/O exception occurs during writing to the writer. */ public void process(Object rootMap, Writer out, ObjectWrapper wrapper) throws TemplateException, IOException { process(rootMap, out, wrapper, null); } /** * Creates a {@link freemarker.core.Environment Environment} object, * using this template, the data model provided as the root map object, and * the supplied object wrapper to convert map elements to template models. * You can then call Environment.process() on the returned environment * to set off the actual rendering. * Use this method if you want to do some special initialization on the environment * before template processing, or if you want to read the environment after template * processing. * *

Example: * *

This: *

    * Environment env = myTemplate.createProcessingEnvironment(root, out, null);
    * env.process();
    * 
* is equivalent with this: *
    * myTemplate.process(root, out);
    * 
* But with createProcessingEnvironment, you can manipulate the environment * before and after the processing: *
    * Environment env = myTemplate.createProcessingEnvironment(root, out);
    * env.include("include/common.ftl", null, true);  // before processing
    * env.process();
    * TemplateModel x = env.getVariable("x");  // after processing
    * 
* * @param rootMap the root node of the data model. If null, an * empty data model is used. Can be any object that the effective object * wrapper can turn into a TemplateHashModel Basically, simple and * beans wrapper can turn java.util.Map objects into hashes * and the Jython wrapper can turn both a PyDictionary as well as any * object that implements __getitem__ into a template hash. * Naturally, you can pass any object directly implementing * TemplateHashModel as well. * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper retrieved * by {@link Configurable#getObjectWrapper()} is used. * @param out the writer to output the text to. * @return the {@link freemarker.core.Environment Environment} object created for processing * @throws TemplateException if an exception occurs while setting up the Environment object. * @throws IOException if an exception occurs doing any auto-imports */ public Environment createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper) throws TemplateException, IOException { TemplateHashModel root = null; if(rootMap instanceof TemplateHashModel) { root = (TemplateHashModel)rootMap; } else { if(wrapper == null) { wrapper = getObjectWrapper(); } try { root = rootMap != null ? (TemplateHashModel)wrapper.wrap(rootMap) : new SimpleHash(wrapper); if(root == null) { throw new IllegalArgumentException(wrapper.getClass().getName() + " converted " + rootMap.getClass().getName() + " to null."); } } catch(ClassCastException e) { throw new IllegalArgumentException(wrapper.getClass().getName() + " could not convert " + rootMap.getClass().getName() + " to a TemplateHashModel."); } } return new Environment(this, root, out); } /** * Same as createProcessingEnvironment(rootMap, out, null). * @see #createProcessingEnvironment(Object rootMap, Writer out, ObjectWrapper wrapper) */ public Environment createProcessingEnvironment(Object rootMap, Writer out) throws TemplateException, IOException { return createProcessingEnvironment(rootMap, out, null); } /** * Returns a string representing the raw template * text in canonical form. */ public String toString() { StringWriter sw = new StringWriter(); try { dump(sw); } catch (IOException ioe) { throw new RuntimeException(ioe.getMessage()); } return sw.toString(); } /** * The path of the template file relative to the directory what you use to store the templates. * For example, if the real path of template is "/www/templates/community/forum.fm", * and you use ""/www/templates" as * {@link Configuration#setDirectoryForTemplateLoading "directoryForTemplateLoading"}, * then name should be "community/forum.fm". The name is used for example when you * use <include ...> and you give a path that is relative to the current * template, or in error messages when FreeMarker logs an error while it processes the template. */ public String getName() { return name; } /** * Returns the Configuration object associated with this template. */ public Configuration getConfiguration() { return (Configuration) getParent(); } /** * Sets the character encoding to use for * included files. Usually you don't set this value manually, * instead it is assigned to the template upon loading. */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * Returns the character encoding used for reading included files. */ public String getEncoding() { return this.encoding; } /** * Dump the raw template in canonical form. */ public void dump(PrintStream ps) { ps.print(rootElement.getCanonicalForm()); } /** * Dump the raw template in canonical form. */ public void dump(Writer out) throws IOException { out.write(rootElement.getCanonicalForm()); } /** * Called by code internally to maintain * a table of macros */ public void addMacro(Macro macro) { macros.put(macro.getName(), macro); } /** * Called by code internally to maintain * a list of imports */ public void addImport(LibraryLoad ll) { imports.add(ll); } /** * Returns the template source at the location * specified by the coordinates given. * @param beginColumn the first column of the requested source, 1-based * @param beginLine the first line of the requested source, 1-based * @param endColumn the last column of the requested source, 1-based * @param endLine the last line of the requested source, 1-based * @see freemarker.core.TemplateObject#getSource() */ public String getSource(int beginColumn, int beginLine, int endColumn, int endLine) { // Our container is zero-based. --beginLine; --beginColumn; --endColumn; --endLine; StringBuffer buf = new StringBuffer(); for (int i = beginLine ; i<=endLine; i++) { if (i < lines.size()) { buf.append(lines.get(i)); } } int lastLineLength = lines.get(endLine).toString().length(); int trailingCharsToDelete = lastLineLength - endColumn -1; buf.delete(0, beginColumn); buf.delete(buf.length() - trailingCharsToDelete, buf.length()); return buf.toString(); } /** * This is a helper class that builds up the line table * info for us. */ private class LineTableBuilder extends FilterReader { StringBuffer lineBuf = new StringBuffer(); int lastChar; /** * @param r the character stream to wrap */ LineTableBuilder(Reader r) { super(r); } public int read() throws IOException { int c = in.read(); handleChar(c); return c; } public int read(char cbuf[], int off, int len) throws IOException { int numchars = in.read(cbuf, off, len); for (int i=off; i < off+numchars; i++) { char c = cbuf[i]; handleChar(c); } return numchars; } public void close() throws IOException { if (lineBuf.length() >0) { lines.add(lineBuf.toString()); lineBuf.setLength(0); } super.close(); } private void handleChar(int c) { if (c == '\n' || c == '\r') { if (lastChar == '\r' && c == '\n') { // CRLF under Windoze int lastIndex = lines.size() -1; String lastLine = (String) lines.get(lastIndex); lines.set(lastIndex, lastLine + '\n'); } else { lineBuf.append((char) c); lines.add(lineBuf.toString()); lineBuf.setLength(0); } } else if (c == '\t') { int numSpaces = 8 - (lineBuf.length() %8); for (int i=0; iTIME, * DATE, or DATETIME. */ public int getDateType(); } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleHash.java0000644000175000017500000003151211723544467025272 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.Serializable; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import freemarker.ext.beans.BeansWrapper; /** *

A simple implementation of the TemplateHashModelEx * interface, using an underlying {@link Map} or {@link SortedMap}.

* *

This class is thread-safe if you don't call the put or remove methods * after you have made the object available for multiple threads. * *

Note:
* As of 2.0, this class is unsynchronized by default. * To obtain a synchronized wrapper, call the {@link #synchronizedWrapper} method.

* * @version $Id: SimpleHash.java,v 1.72.2.2 2006/02/26 18:26:18 revusky Exp $ * @see SimpleSequence * @see SimpleScalar */ public class SimpleHash extends WrappingTemplateModel implements TemplateHashModelEx, Serializable { private Map map; private boolean putFailed; private Map unwrappedMap; /** * Constructs an empty hash that uses the default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}. */ public SimpleHash() { this((ObjectWrapper)null); } /** * Creates a new simple hash with the copy of the underlying map and the * default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}. * @param map The Map to use for the key/value pairs. It makes a copy for * internal use. If the map implements the {@link SortedMap} interface, the * internal copy will be a {@link TreeMap}, otherwise it will be a * {@link HashMap}. */ public SimpleHash(Map map) { this(map, null); } /** * Creates an empty simple hash using the specified object wrapper. * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)} is * used. */ public SimpleHash(ObjectWrapper wrapper) { super(wrapper); map = new HashMap(); } /** * Creates a new simple hash with the copy of the underlying map and * either the default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)}, or * the {@link freemarker.ext.beans.BeansWrapper JavaBeans wrapper}. * @param map The Map to use for the key/value pairs. It makes a copy for * internal use. If the map implements the {@link SortedMap} interface, the * internal copy will be a {@link TreeMap}, otherwise it will be a * @param wrapper The object wrapper to use to wrap objects into * {@link TemplateModel} instances. If null, the default wrapper set in * {@link WrappingTemplateModel#setDefaultObjectWrapper(ObjectWrapper)} is * used. */ public SimpleHash(Map map, ObjectWrapper wrapper) { super(wrapper); try { this.map = copyMap(map); } catch (ConcurrentModificationException cme) { //This will occur extremely rarely. //If it does, we just wait 5 ms and try again. If // the ConcurrentModificationException // is thrown again, we just let it bubble up this time. // TODO: Maybe we should log here. try { Thread.sleep(5); } catch (InterruptedException ie) { } synchronized (map) { this.map = copyMap(map); } } } protected Map copyMap(Map map) { if (map instanceof HashMap) { return (Map) ((HashMap) map).clone(); } if (map instanceof SortedMap) { if (map instanceof TreeMap) { return (Map) ((TreeMap) map).clone(); } else { return new TreeMap((SortedMap) map); } } return new HashMap(map); } /** * Adds a key-value entry to the map. * * @param key the name by which the object is * identified in the template. * @param obj the object to store. */ public void put(String key, Object obj) { map.put(key, obj); unwrappedMap = null; } /** * Puts a boolean in the map * * @param key the name by which the resulting TemplateModel * is identified in the template. * @param b the boolean to store. */ public void put(String key, boolean b) { put(key, b ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE); } public TemplateModel get(String key) throws TemplateModelException { Object result = map.get(key); // The key to use for putting -- it is the key that already exists in // the map (either key or charKey below). This way, we'll never put a // new key in the map, avoiding spurious ConcurrentModificationException // from another thread iterating over the map, see bug #1939742 in // SourceForge tracker. final Object putKey; if (result == null) { if(key.length() == 1) { // just check for Character key if this is a single-character string Character charKey = new Character(key.charAt(0)); result = map.get(charKey); if (result == null && !(map.containsKey(key) || map.containsKey(charKey))) { return null; } else { putKey = charKey; } } else if(!map.containsKey(key)) { return null; } else { putKey = key; } } else { putKey = key; } if (result instanceof TemplateModel) { return (TemplateModel) result; } TemplateModel tm = wrap(result); if (!putFailed) { try { map.put(putKey, tm); } catch (Exception e) { // If it's immutable or something, we just keep going. putFailed = true; } } return tm; } /** * Removes the given key from the underlying map. * * @param key the key to be removed */ public void remove(String key) { map.remove(key); } /** * Adds all the key/value entries in the map * @param m the map with the entries to add, the keys are assumed to be strings. */ public void putAll(Map m) { for (Iterator it = m.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); this.put((String) entry.getKey(), entry.getValue()); } } /** * Note that this method creates and returns a deep-copy of the underlying hash used * internally. This could be a gotcha for some people * at some point who want to alter something in the data model, * but we should maintain our immutability semantics (at least using default SimpleXXX wrappers) * for the data model. It will recursively unwrap the stuff in the underlying container. */ public Map toMap() throws TemplateModelException { if (unwrappedMap == null) { Class mapClass = this.map.getClass(); Map m = null; try { m = (Map) mapClass.newInstance(); } catch (Exception e) { throw new TemplateModelException("Error instantiating map of type " + mapClass.getName() + "\n" + e.getMessage()); } // Create a copy to maintain immutability semantics and // Do nested unwrapping of elements if necessary. BeansWrapper bw = BeansWrapper.getDefaultInstance(); for (Iterator it = map.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); Object key = entry.getKey(); Object value = entry.getValue(); if (value instanceof TemplateModel) { value = bw.unwrap((TemplateModel) value); } m.put(key, value); } unwrappedMap=m; } return unwrappedMap; } /** * Convenience method for returning the String value of the * underlying map. */ public String toString() { return map.toString(); } public int size() { return map.size(); } public boolean isEmpty() { return map == null || map.isEmpty(); } public TemplateCollectionModel keys() { return new SimpleCollection(map.keySet(), getObjectWrapper()); } public TemplateCollectionModel values() { return new SimpleCollection(map.values(), getObjectWrapper()); } public SimpleHash synchronizedWrapper() { return new SynchronizedHash(); } private class SynchronizedHash extends SimpleHash { public boolean isEmpty() { synchronized (SimpleHash.this) { return SimpleHash.this.isEmpty(); } } public void put(String key, Object obj) { synchronized (SimpleHash.this) { SimpleHash.this.put(key, obj); } } public TemplateModel get(String key) throws TemplateModelException { synchronized (SimpleHash.this) { return SimpleHash.this.get(key); } } public void remove(String key) { synchronized (SimpleHash.this) { SimpleHash.this.remove(key); } } public int size() { synchronized (SimpleHash.this) { return SimpleHash.this.size(); } } public TemplateCollectionModel keys() { synchronized (SimpleHash.this) { return SimpleHash.this.keys(); } } public TemplateCollectionModel values() { synchronized (SimpleHash.this) { return SimpleHash.this.values(); } } public Map toMap() throws TemplateModelException { synchronized (SimpleHash.this) { return SimpleHash.this.toMap(); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateModelIterator.java0000644000175000017500000000641511723544471027502 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * This interface is used to iterate over a set of template models, and is usually * returned from an instance of {@link TemplateCollectionModel}. * @author Attila Szegedi, szegedia at users dot sourceforge dot net * @version $Id: TemplateModelIterator.java,v 1.10 2003/01/12 23:40:21 revusky Exp $ */ public interface TemplateModelIterator { /** * Returns the next model. * @throws TemplateModelException if the next model can not be retrieved * (i.e. because the iterator is exhausted). */ TemplateModel next() throws TemplateModelException; /** * @return whether there are any more items to iterate over. */ boolean hasNext() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleDate.java0000644000175000017500000001006311723544467025262 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * A simple implementation of the TemplateDateModel * interface. Note that this class is immutable. *

This class is thread-safe. * * @version $Id: SimpleDate.java,v 1.11 2004/03/13 13:05:09 ddekany Exp $ * @author Attila Szegedi */ public class SimpleDate implements TemplateDateModel { private final java.util.Date date; private final int type; /** * Creates a new date model wrapping the specified date object and * having DATE type. */ public SimpleDate(java.sql.Date date) { this(date, DATE); } /** * Creates a new date model wrapping the specified time object and * having TIME type. */ public SimpleDate(java.sql.Time time) { this(time, TIME); } /** * Creates a new date model wrapping the specified time object and * having DATETIME type. */ public SimpleDate(java.sql.Timestamp datetime) { this(datetime, DATETIME); } /** * Creates a new date model wrapping the specified date object and * having the specified type. */ public SimpleDate(java.util.Date date, int type) { if(date == null) { throw new IllegalArgumentException("date == null"); } this.date = date; this.type = type; } public java.util.Date getAsDate() { return date; } public int getDateType() { return type; } public String toString() { return date.toString(); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateDirectiveModel.java0000644000175000017500000000432111723544467027626 0ustar ebourgebourgpackage freemarker.template; import java.io.IOException; import java.util.Map; import freemarker.core.Environment; import freemarker.template.utility.DeepUnwrap; /** * Objects that implement this interface can be used as user-defined directives * (much like macros). They can do arbitrary actions, write arbitrary * text to the template output, and trigger rendering of their nested content * any number of times. * * @since 2.3.11 * @author Attila Szegedi * @version $Id: $ */ public interface TemplateDirectiveModel extends TemplateModel { /** * Executes this user-defined directive; called by FreeMarker when the user-defined * directive is called in the template. * * @param env the current processing environment. Note that you can access * the output {@link java.io.Writer Writer} by {@link Environment#getOut()}. * @param params the parameters (if any) passed to the directive as a * map of key/value pairs where the keys are {@link String}-s and the * values are {@link TemplateModel} instances. This is never * null. If you need to convert the template models to POJOs, * you can use the utility methods in the {@link DeepUnwrap} class. * @param loopVars an array that corresponds to the "loop variables", in * the order as they appear in the directive call. ("Loop variables" are out-parameters * that are available to the nested body of the directive; see in the Manual.) * You set the loop variables by writing this array. The length of the array gives the * number of loop-variables that the caller has specified. * Never null, but can be a zero-length array. * @param body an object that can be used to render the nested content (body) of * the directive call. If the directive call has no nested content (i.e., it is like * [@myDirective /] or [@myDirective][/@myDirective]), then this will be * null. * * @throws TemplateException * @throws IOException */ public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException; }libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateNodeModel.java0000644000175000017500000001131111723544471026565 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * Describes objects that are nodes in a tree. * If you have a tree of objects, they can be recursively * visited using the <#visit...> and <#recurse...> * FTL directives. This API is largely based on the W3C Document Object Model * (DOM) API. However, it is meant to be generally useful for describing * any tree of objects that you wish to navigate using a recursive visitor * design pattern. * @since FreeMarker 2.3 * @author Jonathan Revusky */ public interface TemplateNodeModel extends TemplateModel { /** * @return the parent of this node or null, in which case * this node is the root of the tree. */ TemplateNodeModel getParentNode() throws TemplateModelException; /** * @return a sequence containing this node's children. * If the returned value is null or empty, this is essentially * a leaf node. */ TemplateSequenceModel getChildNodes() throws TemplateModelException; /** * @return a String that is used to determine the processing * routine to use. In the XML implementation, if the node * is an element, it returns the element's tag name. If it * is an attribute, it returns the attribute's name. It * returns "@text" for text nodes, "@pi" for processing instructions, * and so on. */ String getNodeName() throws TemplateModelException; /** * @return a String describing the type of node this is. * In the W3C DOM, this should be "element", "text", "attribute", etc. * A TemplateNodeModel implementation that models other kinds of * trees could return whatever it appropriate for that application. It * can be null, if you don't want to use node-types. */ String getNodeType() throws TemplateModelException; /** * @return the XML namespace URI with which this node is * associated. If this TemplateNodeModel implementation is * not XML-related, it will almost certainly be null. Even * for XML nodes, this will often be null. */ String getNodeNamespace() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/debug/0000755000175000017500000000000012164627123023445 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/template/debug/package.html0000644000175000017500000000034111723544470025727 0ustar ebourgebourg

The beginnings of a debugging API. This will support visual tools such as a visual debugging console -- one of various ideas mentioned on the FM-devel list.

libfreemarker-java-2.3.19.orig/src/freemarker/template/DefaultObjectWrapper.java0000644000175000017500000001413711723544471027310 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Map; import freemarker.ext.dom.NodeModel; /** *

The default implementation of the ObjectWrapper * interface. * * @version $Id: DefaultObjectWrapper.java,v 1.23 2005/06/08 00:06:19 revusky Exp $ */ public class DefaultObjectWrapper extends freemarker.ext.beans.BeansWrapper { static final DefaultObjectWrapper instance = new DefaultObjectWrapper(); static private Class W3C_DOM_NODE_CLASS, JYTHON_OBJ_CLASS; static private ObjectWrapper JYTHON_WRAPPER; static { try { W3C_DOM_NODE_CLASS = Class.forName("org.w3c.dom.Node"); } catch (Exception e) {} try { JYTHON_OBJ_CLASS = Class.forName("org.python.core.PyObject"); JYTHON_WRAPPER = (ObjectWrapper) Class.forName( "freemarker.ext.jython.JythonWrapper") .getField("INSTANCE").get(null); } catch (Exception e) {} } public TemplateModel wrap(Object obj) throws TemplateModelException { if (obj == null) { return super.wrap(null); } if (obj instanceof TemplateModel) { return (TemplateModel) obj; } if (obj instanceof String) { return new SimpleScalar((String) obj); } if (obj instanceof Number) { return new SimpleNumber((Number) obj); } if (obj instanceof java.util.Date) { if(obj instanceof java.sql.Date) { return new SimpleDate((java.sql.Date) obj); } if(obj instanceof java.sql.Time) { return new SimpleDate((java.sql.Time) obj); } if(obj instanceof java.sql.Timestamp) { return new SimpleDate((java.sql.Timestamp) obj); } return new SimpleDate((java.util.Date) obj, getDefaultDateType()); } if (obj.getClass().isArray()) { obj = convertArray(obj); } if (obj instanceof Collection) { return new SimpleSequence((Collection) obj, this); } if (obj instanceof Map) { return new SimpleHash((Map) obj, this); } if (obj instanceof Boolean) { return obj.equals(Boolean.TRUE) ? TemplateBooleanModel.TRUE : TemplateBooleanModel.FALSE; } if (obj instanceof Iterator) { return new SimpleCollection((Iterator) obj, this); } return handleUnknownType(obj); } /** * Called if an unknown type is passed in. * Since 2.3, this falls back on XML wrapper and BeansWrapper functionality. */ protected TemplateModel handleUnknownType(Object obj) throws TemplateModelException { if ((W3C_DOM_NODE_CLASS != null && W3C_DOM_NODE_CLASS.isInstance(obj))) { return wrapDomNode(obj); } if (JYTHON_WRAPPER != null && JYTHON_OBJ_CLASS.isInstance(obj)) { return JYTHON_WRAPPER.wrap(obj); } return super.wrap(obj); } public TemplateModel wrapDomNode(Object obj) { return NodeModel.wrap((org.w3c.dom.Node) obj); } /** * Converts an array to a java.util.List */ protected Object convertArray(Object arr) { final int size = Array.getLength(arr); ArrayList list = new ArrayList(size); for (int i=0;iJonathan Revusky */ final class GeneralPurposeNothing implements TemplateBooleanModel, TemplateScalarModel, TemplateSequenceModel, TemplateHashModelEx, TemplateMethodModelEx { private static final TemplateModel instance = new GeneralPurposeNothing(); private static final TemplateCollectionModel EMPTY_COLLECTION = new SimpleCollection(new ArrayList(0)); private GeneralPurposeNothing() { } static TemplateModel getInstance() { return instance; } public String getAsString() { return ""; } public boolean getAsBoolean() { return false; } public boolean isEmpty() { return true; } public int size() { return 0; } public TemplateModel get(int i) throws TemplateModelException { throw new TemplateModelException("Empty list"); } public TemplateModel get(String key) { return null; } public Object exec(List args) { return null; } public TemplateCollectionModel keys() { return EMPTY_COLLECTION; } public TemplateCollectionModel values() { return EMPTY_COLLECTION; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateModel.java0000644000175000017500000000631211723544467025771 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** *

This is a marker interface that indicates that an object * can be put in a template's data model. * * @see TemplateHashModel * @see TemplateSequenceModel * @see TemplateCollectionModel * @see TemplateScalarModel * @see TemplateNumberModel * @see TemplateTransformModel * * @version $Id: TemplateModel.java,v 1.19 2003/01/12 23:40:21 revusky Exp $ */ public interface TemplateModel { /** * A general-purpose object to represent nothing. It acts as * an empty string, false, empty sequence, empty hash, and * null-returning method model. */ TemplateModel NOTHING = GeneralPurposeNothing.getInstance(); } libfreemarker-java-2.3.19.orig/src/freemarker/template/EmptyMap.java0000644000175000017500000000245311723544470024765 0ustar ebourgebourgpackage freemarker.template; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Set; public class EmptyMap implements Map, Cloneable { public static final EmptyMap instance = new EmptyMap(); public void clear() { throw new UnsupportedOperationException("This Map is read-only."); } public boolean containsKey(Object arg0) { return false; } public boolean containsValue(Object arg0) { return false; } public Set entrySet() { return Collections.EMPTY_SET; } public Object get(Object arg0) { return null; } public boolean isEmpty() { return true; } public Set keySet() { return Collections.EMPTY_SET; } public Object put(Object arg0, Object arg1) { throw new UnsupportedOperationException("This Map is read-only."); } public void putAll(Map arg0) { throw new UnsupportedOperationException("This Map is read-only."); } public Object remove(Object arg0) { throw new UnsupportedOperationException("This Map is read-only."); } public int size() { return 0; } public Collection values() { return Collections.EMPTY_LIST; } } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateMethodModel.java0000644000175000017500000000760511723544470027132 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ /* * 22 October 1999: This class added by Holger Arendt. */ package freemarker.template; import java.util.List; import freemarker.core.Environment; /** * Objects that act as methods in a template data model must implement this * interface. * @version $Id: TemplateMethodModel.java,v 1.11 2003/09/22 23:56:54 revusky Exp $ */ public interface TemplateMethodModel extends TemplateModel { /** * Executes a method call. All arguments passed to the method call are * coerced to strings before being passed, if the FreeMarker rules allow * the coercion. If some of the passed arguments can not be coerced to a * string, an exception will be raised in the engine and the method will * not be called. If your method would like to act on actual data model * objects instead of on their string representations, implement the * {@link TemplateMethodModelEx} instead. * @param arguments a List of String objects * containing the values of the arguments passed to the method. * @return the return value of the method, or null. If the returned value * does not implement {@link TemplateModel}, it will be automatically * wrapped using the {@link Environment#getObjectWrapper() environment * object wrapper}. */ public Object exec(List arguments) throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateNumberModel.java0000644000175000017500000000613111723544470027133 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** * Numeric values in a template data model must implement this interface. * * @author Jonathan Revusky * * @version $Id: TemplateNumberModel.java,v 1.14 2004/11/27 14:49:57 ddekany Exp $ */ public interface TemplateNumberModel extends TemplateModel { /** * Returns the numeric value. The return value must not be null. * * @return the {@link Number} instance associated with this number model. */ public Number getAsNumber() throws TemplateModelException; } libfreemarker-java-2.3.19.orig/src/freemarker/template/TransformControl.java0000644000175000017500000001335411723544470026547 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.IOException; /** * An interface that can be implemented by writers returned from * {@link TemplateTransformModel#getWriter(java.io.Writer, java.util.Map)}. The * methods on this * interfaces are callbacks that will be called by the template engine and that * give the writer a chance to better control the evaluation of the transform * body. The writer can instruct the engine to skip or to repeat body * evaluation, and gets notified about exceptions that are thrown during the * body evaluation. * * @author Attila Szegedi * @version $Id: TransformControl.java,v 1.11 2005/06/16 18:13:58 ddekany Exp $ */ public interface TransformControl { /** * Constant returned from {@link #afterBody()} that tells the * template engine to repeat transform body evaluation and feed * it again to the transform. */ public static final int REPEAT_EVALUATION = 0; /** * Constant returned from {@link #afterBody()} that tells the * template engine to end the transform and close the writer. */ public static final int END_EVALUATION = 1; /** * Constant returned from {@link #onStart()} that tells the * template engine to skip evaluation of the body. */ public static final int SKIP_BODY = 0; /** * Constant returned from {@link #onStart()} that tells the * template engine to evaluate the body. */ public static final int EVALUATE_BODY = 1; /** * Called before the body is evaluated for the first time. * @return *

    *
  • SKIP_BODY if the transform wants to ignore the body. In this * case, only {@link java.io.Writer#close()} is called next and processing ends.
  • *
  • EVALUATE_BODY to normally evaluate the body of the transform * and feed it to the writer
  • *
*/ public int onStart() throws TemplateModelException, IOException; /** * Called after the body has been evaluated. * @return *
    *
  • END_EVALUATION if the transformation should be ended.
  • *
  • REPEAT_EVALUATION to have the engine re-evaluate the * transform body and feed it again to the writer.
  • *
*/ public int afterBody() throws TemplateModelException, IOException; /** * Called if any exception occurs during the transform between the * {@link TemplateTransformModel#getWriter(java.io.Writer, java.util.Map)} call * and the {@link java.io.Writer#close()} call. * @param t the throwable that represents the exception. It can be any * non-checked throwable, as well as {@link TemplateException} and * {@link java.io.IOException}. * * @throws Throwable is recommended that the methods rethrow the received * throwable. If the method wants to throw another throwable, it should * either throw a non-checked throwable, or an instance of * {@link TemplateException} and {@link java.io.IOException}. Throwing any * other checked exception will cause the engine to rethrow it as * a {@link java.lang.reflect.UndeclaredThrowableException}. */ public void onError(Throwable t) throws Throwable; } libfreemarker-java-2.3.19.orig/src/freemarker/template/package.html0000644000175000017500000000110011723544467024641 0ustar ebourgebourg

This package contains the core API's that most users will use.

The typical usage pattern is to be vended {@link freemarker.template.Template} objects by the {@link freemarker.template.Configuration} object. The Template class represents a template file compiled into an efficient data structure for later use. Processing of compiled templates is very fast.

For complete instructions on how to use this package, please see the manual. libfreemarker-java-2.3.19.orig/src/freemarker/template/TemplateException.java0000644000175000017500000002136011723544470026661 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import freemarker.core.Environment; /** * The FreeMarker classes usually use this exception and its descendants to * signal FreeMarker specific exceptions. * * @version $Id: TemplateException.java,v 1.26.2.1 2006/02/12 20:02:15 revusky Exp $ */ public class TemplateException extends Exception { private static final boolean BEFORE_1_4 = before14(); private static boolean before14() { Class ec = Exception.class; try { ec.getMethod("getCause", new Class[]{}); } catch (Throwable e) { return true; } return false; } private static final Class[] EMPTY_CLASS_ARRAY = new Class[]{}; private static final Object[] EMPTY_OBJECT_ARRAY = new Object[]{}; /** The underlying cause of this exception, if any */ private final Exception causeException; private final transient Environment env; private final String ftlInstructionStack; /** * Constructs a TemplateException with no specified detail message * or underlying cause. */ public TemplateException(Environment env) { this(null, null, env); } /** * Constructs a TemplateException with the given detail message, * but no underlying cause exception. * * @param description the description of the error that occurred */ public TemplateException(String description, Environment env) { this(description, null, env); } /** * Constructs a TemplateException with the given underlying Exception, * but no detail message. * * @param cause the underlying Exception that caused this * exception to be raised */ public TemplateException(Exception cause, Environment env) { this(null, cause, env); } /** * Constructs a TemplateException with both a description of the error * that occurred and the underlying Exception that caused this exception * to be raised. * * @param description the description of the error that occurred * @param cause the underlying Exception that caused this * exception to be raised */ public TemplateException(String description, Exception cause, Environment env) { super(getDescription(description, cause)); causeException = cause; this.env = env; if(env != null) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); env.outputInstructionStack(pw); pw.flush(); ftlInstructionStack = sw.toString(); } else { ftlInstructionStack = ""; } } private static String getDescription(String description, Exception cause) { if(description != null) { return description; } if(cause != null) { return cause.getClass().getName() + ": " + cause.getMessage(); } return "No error message"; } /** *

Returns the underlying exception that caused this exception to be * generated.

*

Note:
* avoided calling it getCause to avoid name clash with * JDK 1.4 method. This would be problematic because the JDK 1.4 method * returns a Throwable rather than an Exception.

* * @return the underlying Exception, if any, that caused this * exception to be raised */ public Exception getCauseException() { return causeException; } /** * Returns the same exception as getCauseException. Provided * to enable full JDK-generated stack traces when running under JDK 1.4. * * @see Throwable#getCause() * @return the underlying Exception, if any, that caused this * exception to be raised */ public Throwable getCause() { return causeException; } /** * Returns the quote of the problematic FTL instruction and the FTL stack strace. */ public String getFTLInstructionStack() { return ftlInstructionStack; } /** * @return the execution environment in which the exception occurred. * null if the exception was deserialized. */ public Environment getEnvironment() { return env; } public void printStackTrace(java.io.PrintStream ps) { PrintWriter pw = new PrintWriter(new OutputStreamWriter(ps), true); printStackTrace(pw); pw.flush(); } public void printStackTrace(PrintWriter pw) { pw.println(); pw.println(getMessage()); if (ftlInstructionStack != null && ftlInstructionStack.length() != 0) { pw.println("The problematic instruction:"); pw.println(ftlInstructionStack); } pw.println("Java backtrace for programmers:"); pw.println("----------"); super.printStackTrace(pw); if (BEFORE_1_4 && causeException != null) { pw.println("Underlying cause: "); causeException.printStackTrace(pw); } // Dirty hack to fight with stupid ServletException class whose // getCause() method doesn't work properly. Also an aid for pre-J2xE 1.4 // users. try { // Reflection is used to prevent dependency on Servlet classes. Method m = causeException.getClass().getMethod("getRootCause", EMPTY_CLASS_ARRAY); Throwable rootCause = (Throwable) m.invoke(causeException, EMPTY_OBJECT_ARRAY); if (rootCause != null) { Throwable j14Cause = null; if (!BEFORE_1_4) { m = causeException.getClass().getMethod("getCause", EMPTY_CLASS_ARRAY); j14Cause = (Throwable) m.invoke(causeException, EMPTY_OBJECT_ARRAY); } if (j14Cause == null) { pw.println("ServletException root cause: "); rootCause.printStackTrace(pw); } } } catch (Throwable exc) { ; // ignore } } } libfreemarker-java-2.3.19.orig/src/freemarker/template/SimpleObjectWrapper.java0000644000175000017500000000645211723544471027156 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.template; /** *

The default implementation of the ObjectWrapper * interface. * * @version $Id: SimpleObjectWrapper.java,v 1.24 2003/05/30 16:29:44 szegedia Exp $ */ public class SimpleObjectWrapper extends DefaultObjectWrapper { static final SimpleObjectWrapper instance = new SimpleObjectWrapper(); /** * Called if a type other than the simple ones we know about is passed in. * In this implementation, this just throws an exception. */ protected TemplateModel handleUnknownType(Object obj) throws TemplateModelException { throw new TemplateModelException("Don't know how to present an object of this type to a template: " + obj.getClass().getName()); } } libfreemarker-java-2.3.19.orig/src/freemarker/template/ResourceBundleLocalizedString.java0000644000175000017500000000221711723544471031167 0ustar ebourgebourgpackage freemarker.template; import java.util.Locale; import java.util.ResourceBundle; import java.util.MissingResourceException; /** * A concrete implementation of {@link LocalizedString} that gets * a localized string from a {@link java.util.ResourceBundle} * @author Jonathan Revusky */ public class ResourceBundleLocalizedString extends LocalizedString { private String resourceKey, resourceBundleLookupKey; /** * @param resourceBundleLookupKey The lookup key for the resource bundle * @param resourceKey the specific resource (assumed to be a string) to fish out of the resource bundle */ public ResourceBundleLocalizedString(String resourceBundleLookupKey, String resourceKey) { this.resourceBundleLookupKey = resourceBundleLookupKey; this.resourceKey = resourceKey; } public String getLocalizedString(Locale locale) throws TemplateModelException { try { ResourceBundle rb = ResourceBundle.getBundle(resourceBundleLookupKey, locale); return rb.getString(resourceKey); } catch (MissingResourceException mre) { throw new TemplateModelException("missing resource", mre); } } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/0000755000175000017500000000000012164627123021607 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/freemarker/cache/StringTemplateLoader.java0000644000175000017500000001653211723544471026556 0ustar ebourgebourg/* * Copyright (c) 2005 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.Reader; import java.io.StringReader; import java.util.HashMap; import java.util.Map; /** * A {@link TemplateLoader} that uses a Map with Strings as its source of * templates. * * In most case the regular way of loading templates from files will be fine. * However, there can be situations where you don't want to or can't load a * template from a file, e.g. if you have to deploy a single jar for * JavaWebStart or if they are contained within a database. * A single template can be created manually * e.g. *

 *   String templateStr="Hello ${user}";
 *   Template t = new Template("name", new StringReader(templateStr),
 *               new Configuration());
 * 
* If, however, you want to create templates from strings which import other * templates this method doesn't work. * * In that case you can create a StringTemplateLoader and add each template to * it: *
 *   StringTemplateLoader stringLoader = new StringTemplateLoader();
 *   stringLoader.putTemplate("greetTemplate", "<#macro greet>Hello");
 *   stringLoader.putTemplate("myTemplate", "<#include \"greetTemplate\"><@greet/> World!");
 * 
* Then you tell your Configuration object to use it: *
 *   cfg.setTemplateLoader(stringLoader);
 * 
* After that you should be able to use the templates as usual. Often you will * want to combine a StringTemplateLoader with another loader. You can * do so using a {@link freemarker.cache.MultiTemplateLoader}. * * @version $Id: v 1.0 2005/04/01 * @author Meikel Bisping * @author Attila Szegedi * @version $Id: StringTemplateLoader.java,v 1.1 2005/04/08 11:47:53 szegedia Exp $ */ public class StringTemplateLoader implements TemplateLoader { private final Map templates = new HashMap(); /** * Puts a template into the loader. A call to this method is identical to * the call to the three-arg {@link #putTemplate(String, String, long)} * passing System.currentTimeMillis() as the third argument. * @param name the name of the template. * @param templateSource the source code of the template. */ public void putTemplate(String name, String templateSource) { putTemplate(name, templateSource, System.currentTimeMillis()); } /** * Puts a template into the loader. The name can contain slashes to denote * logical directory structure, but must not start with a slash. If the * method is called multiple times for the same name and with different * last modified time, the configuration's template cache will reload the * template according to its own refresh settings (note that if the refresh * is disabled in the template cache, the template will not be reloaded). * Also, since the cache uses lastModified to trigger reloads, calling the * method with different source and identical timestamp won't trigger * reloading. * @param name the name of the template. * @param templateSource the source code of the template. * @param lastModified the time of last modification of the template in * terms of System.currentTimeMillis() */ public void putTemplate(String name, String templateSource, long lastModified) { templates.put(name, new StringTemplateSource(name, templateSource, lastModified)); } public void closeTemplateSource(Object templateSource) { } public Object findTemplateSource(String name) { return templates.get(name); } public long getLastModified(Object templateSource) { return ((StringTemplateSource)templateSource).lastModified; } public Reader getReader(Object templateSource, String encoding) { return new StringReader(((StringTemplateSource)templateSource).source); } private static class StringTemplateSource { private final String name; private final String source; private final long lastModified; StringTemplateSource(String name, String source, long lastModified) { if(name == null) { throw new IllegalArgumentException("name == null"); } if(source == null) { throw new IllegalArgumentException("source == null"); } if(lastModified < -1L) { throw new IllegalArgumentException("lastModified < -1L"); } this.name = name; this.source = source; this.lastModified = lastModified; } public boolean equals(Object obj) { if(obj instanceof StringTemplateSource) { return name.equals(((StringTemplateSource)obj).name); } return false; } public int hashCode() { return name.hashCode(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/ConcurrentMapFactory.java0000644000175000017500000000232111723544471026564 0ustar ebourgebourgpackage freemarker.cache; import java.util.HashMap; import java.util.Map; import freemarker.template.utility.ClassUtil; import freemarker.template.utility.UndeclaredThrowableException; /** * @author Attila Szegedi * @version $Id: $ */ class ConcurrentMapFactory { private static final Class mapClass = getMapClass(); private static final Class hashMapClass = getHashMapClass(); static Map createMap() { try { return (Map)hashMapClass.newInstance(); } catch(Exception e) { throw new UndeclaredThrowableException(e); } } static boolean isConcurrent(Map map) { return mapClass != null && mapClass.isInstance(map); } private static Class getMapClass() { try { return ClassUtil.forName("java.util.concurrent.ConcurrentMap"); } catch(ClassNotFoundException e) { return null; } } private static Class getHashMapClass() { try { return ClassUtil.forName("java.util.concurrent.ConcurrentHashMap"); } catch(ClassNotFoundException e) { return HashMap.class; } } }libfreemarker-java-2.3.19.orig/src/freemarker/cache/SoftCacheStorage.java0000644000175000017500000001354211723544471025647 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import freemarker.template.utility.UndeclaredThrowableException; /** * Soft cache storage is a cache storage that uses {@link SoftReference} * objects to hold the objects it was passed, therefore allows the garbage * collector to purge the cache when it determines that it wants to free up * memory. * This class is thread-safe to the extent that its underlying map is. The * default implementation uses a concurrent map on Java 5 and above, so it is * thread-safe in that case. * * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) * * @author Attila Szegedi */ public class SoftCacheStorage implements ConcurrentCacheStorage { private static final Method atomicRemove = getAtomicRemoveMethod(); private final ReferenceQueue queue = new ReferenceQueue(); private final Map map; private final boolean concurrent; public SoftCacheStorage() { this(ConcurrentMapFactory.createMap()); } public boolean isConcurrent() { return concurrent; } public SoftCacheStorage(Map backingMap) { map = backingMap; this.concurrent = ConcurrentMapFactory.isConcurrent(map); } public Object get(Object key) { processQueue(); Reference ref = (Reference)map.get(key); return ref == null ? null : ref.get(); } public void put(Object key, Object value) { processQueue(); map.put(key, new SoftValueReference(key, value, queue)); } public void remove(Object key) { processQueue(); map.remove(key); } public void clear() { map.clear(); processQueue(); } private void processQueue() { for(;;) { SoftValueReference ref = (SoftValueReference)queue.poll(); if(ref == null) { return; } Object key = ref.getKey(); if(concurrent) { try { atomicRemove.invoke(map, new Object[] { key, ref }); } catch(IllegalAccessException e) { throw new UndeclaredThrowableException(e); } catch(InvocationTargetException e) { throw new UndeclaredThrowableException(e); } } else if(map.get(key) == ref) { map.remove(key); } } } private static final class SoftValueReference extends SoftReference { private final Object key; SoftValueReference(Object key, Object value, ReferenceQueue queue) { super(value, queue); this.key = key; } Object getKey() { return key; } } private static Method getAtomicRemoveMethod() { try { return Class.forName("java.util.concurrent.ConcurrentMap").getMethod("remove", new Class[] { Object.class, Object.class }); } catch(ClassNotFoundException e) { return null; } catch(NoSuchMethodException e) { throw new UndeclaredThrowableException(e); } } }libfreemarker-java-2.3.19.orig/src/freemarker/cache/MruCacheStorage.java0000644000175000017500000002571111723544471025500 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; /** * A cache storage that implements a two-level Most Recently Used cache. In the * first level, items are strongly referenced up to the specified maximum. When * the maximum is exceeded, the least recently used item is moved into the * second level cache, where they are softly referenced, up to another * specified maximum. When the second level maximum is also exceeded, the least * recently used item is discarded altogether. This cache storage is a * generalization of both {@link StrongCacheStorage} and * {@link SoftCacheStorage} - the effect of both of them can be achieved by * setting one maximum to zero and the other to the largest positive integer. * On the other hand, if you wish to use this storage in a strong-only mode, or * in a soft-only mode, you might consider using {@link StrongCacheStorage} or * {@link SoftCacheStorage} instead, as they can be used by * {@link TemplateCache} concurrently without any synchronization on a 5.0 or * later JRE. * This class is NOT thread-safe. If it is accessed from multiple * threads concurrently, proper synchronization must be provided by the callers. * Note that {@link TemplateCache}, the natural user of this class provides the * necessary synchronizations when it uses the class. * Also you might consider whether you need this sort of a mixed storage at all * in your solution, as in most cases SoftCacheStorage can also be sufficient. * SoftCacheStorage will use Java soft references, and they already use access * timestamps internally to bias the garbage collector against clearing * recently used references, so you can get reasonably good (and * memory-sensitive) most-recently-used caching through * {@link SoftCacheStorage} as well. * * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) * * @author Attila Szegedi */ public class MruCacheStorage implements CacheStorage { private final MruEntry strongHead = new MruEntry(); private final MruEntry softHead = new MruEntry(); { softHead.linkAfter(strongHead); } private final Map map = new HashMap(); private final ReferenceQueue refQueue = new ReferenceQueue(); private final int maxStrongSize; private final int maxSoftSize; private int strongSize = 0; private int softSize = 0; /** * Creates a new MRU cache storage with specified maximum cache sizes. Each * cache size can vary between 0 and {@link Integer#MAX_VALUE}. * @param maxStrongSize the maximum number of strongly referenced templates * @param maxSoftSize the maximum number of softly referenced templates */ public MruCacheStorage(int maxStrongSize, int maxSoftSize) { if(maxStrongSize < 0) throw new IllegalArgumentException("maxStrongSize < 0"); if(maxSoftSize < 0) throw new IllegalArgumentException("maxSoftSize < 0"); this.maxStrongSize = maxStrongSize; this.maxSoftSize = maxSoftSize; } public Object get(Object key) { removeClearedReferences(); MruEntry entry = (MruEntry)map.get(key); if(entry == null) { return null; } relinkEntryAfterStrongHead(entry, null); Object value = entry.getValue(); if(value instanceof MruReference) { // This can only happen with maxStrongSize == 0 return ((MruReference)value).get(); } return value; } public void put(Object key, Object value) { removeClearedReferences(); MruEntry entry = (MruEntry)map.get(key); if(entry == null) { entry = new MruEntry(key, value); map.put(key, entry); linkAfterStrongHead(entry); } else { relinkEntryAfterStrongHead(entry, value); } } public void remove(Object key) { removeClearedReferences(); removeInternal(key); } private void removeInternal(Object key) { MruEntry entry = (MruEntry)map.remove(key); if(entry != null) { unlinkEntryAndInspectIfSoft(entry); } } public void clear() { strongHead.makeHead(); softHead.linkAfter(strongHead); map.clear(); strongSize = softSize = 0; // Quick refQueue processing while(refQueue.poll() != null); } private void relinkEntryAfterStrongHead(MruEntry entry, Object newValue) { if(unlinkEntryAndInspectIfSoft(entry) && newValue == null) { // Turn soft reference into strong reference, unless is was cleared MruReference mref = (MruReference)entry.getValue(); Object strongValue = mref.get(); if (strongValue != null) { entry.setValue(strongValue); linkAfterStrongHead(entry); } else { map.remove(mref.getKey()); } } else { if (newValue != null) { entry.setValue(newValue); } linkAfterStrongHead(entry); } } private void linkAfterStrongHead(MruEntry entry) { entry.linkAfter(strongHead); if(strongSize == maxStrongSize) { // softHead.previous is LRU strong entry MruEntry lruStrong = softHead.getPrevious(); // Attila: This is equaivalent to maxStrongSize != 0 // DD: But entry.linkAfter(strongHead) was just excuted above, so // lruStrong != strongHead is true even if maxStrongSize == 0. if(lruStrong != strongHead) { lruStrong.unlink(); if(maxSoftSize > 0) { lruStrong.linkAfter(softHead); lruStrong.setValue(new MruReference(lruStrong, refQueue)); if(softSize == maxSoftSize) { // List is circular, so strongHead.previous is LRU soft entry MruEntry lruSoft = strongHead.getPrevious(); lruSoft.unlink(); map.remove(lruSoft.getKey()); } else { ++softSize; } } else { map.remove(lruStrong.getKey()); } } } else { ++strongSize; } } private boolean unlinkEntryAndInspectIfSoft(MruEntry entry) { entry.unlink(); if(entry.getValue() instanceof MruReference) { --softSize; return true; } else { --strongSize; return false; } } private void removeClearedReferences() { for(;;) { MruReference ref = (MruReference)refQueue.poll(); if(ref == null) { break; } removeInternal(ref.getKey()); } } private static final class MruEntry { private MruEntry prev; private MruEntry next; private final Object key; private Object value; /** * Used solely to construct the head element */ MruEntry() { makeHead(); key = value = null; } MruEntry(Object key, Object value) { this.key = key; this.value = value; } Object getKey() { return key; } Object getValue() { return value; } void setValue(Object value) { this.value = value; } MruEntry getPrevious() { return prev; } void linkAfter(MruEntry entry) { next = entry.next; entry.next = this; prev = entry; next.prev = this; } void unlink() { next.prev = prev; prev.next = next; prev = null; next = null; } void makeHead() { prev = next = this; } } private static class MruReference extends SoftReference { private final Object key; MruReference(MruEntry entry, ReferenceQueue queue) { super(entry.getValue(), queue); this.key = entry.getKey(); } Object getKey() { return key; } } }libfreemarker-java-2.3.19.orig/src/freemarker/cache/URLTemplateSource.java0000644000175000017500000001276011723544471026003 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.JarURLConnection; import java.net.URLConnection; /** * Wraps a java.net.URL, and implements methods required for a typical template source. * @version $Id: URLTemplateSource.java,v 1.4 2003/04/02 11:43:18 szegedia Exp $ * @author Daniel Dekany * @author TJ Laurenzo */ class URLTemplateSource { private final URL url; private URLConnection conn; private InputStream inputStream; URLTemplateSource(URL url) throws IOException { this.url = url; this.conn = url.openConnection(); } public boolean equals(Object o) { if (o instanceof URLTemplateSource) { return url.equals(((URLTemplateSource) o).url); } else { return false; } } public int hashCode() { return url.hashCode(); } public String toString() { return url.toString(); } long lastModified() { if (conn instanceof JarURLConnection) { // There is a bug in sun's jar url connection that causes file handle leaks when calling getLastModified() // Since the time stamps of jar file contents can't vary independent from the jar file timestamp, just use // the jar file timestamp URL jarURL=((JarURLConnection)conn).getJarFileURL(); if (jarURL.getProtocol().equals("file")) { // Return the last modified time of the underlying file - saves some opening and closing return new File(jarURL.getFile()).lastModified(); } else { // Use the URL mechanism URLConnection jarConn=null; try { jarConn=jarURL.openConnection(); return jarConn.getLastModified(); } catch (IOException e) { return -1; } finally { try { if (jarConn!=null) jarConn.getInputStream().close(); } catch (IOException e) { } } } } else { long lastModified = conn.getLastModified(); if (lastModified == -1L && url.getProtocol().equals("file")) { // Hack for obtaining accurate last modified time for // URLs that point to the local file system. This is fixed // in JDK 1.4, but prior JDKs returns -1 for file:// URLs. return new File(url.getFile()).lastModified(); } else { return lastModified; } } } InputStream getInputStream() throws IOException { inputStream = conn.getInputStream(); return inputStream; } void close() throws IOException { try { if (inputStream != null) { inputStream.close(); } else { conn.getInputStream().close(); } } finally { inputStream = null; conn = null; } } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/CacheStorage.java0000644000175000017500000000633011723544471025010 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; /** * Cache storage abstracts away the storage aspects of a cache - associating * an object with a key, retrieval and removal via the key. It is actually a * small subset of the {@link java.util.Map} interface. * The implementations can be coded in a non-threadsafe manner as the natural * user of the cache storage, {@link TemplateCache} does the necessary * synchronization. * * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) * * @author Attila Szegedi */ public interface CacheStorage { public Object get(Object key); public void put(Object key, Object value); public void remove(Object key); public void clear(); } libfreemarker-java-2.3.19.orig/src/freemarker/cache/StatefulTemplateLoader.java0000644000175000017500000000127411723544472027075 0ustar ebourgebourgpackage freemarker.cache; import freemarker.template.Configuration; /** * Interface that can be implemented by template loaders that maintain some * sort of internal state (i.e. caches of earlier lookups for performance * optimization purposes etc.) and support resetting of their state. * @author Attila Szegedi * @version $Id: StatefulTemplateLoader.java,v 1.1.2.1 2007/04/03 18:06:07 szegedia Exp $ */ public interface StatefulTemplateLoader extends TemplateLoader { /** * Invoked by {@link Configuration#clearTemplateCache()} to instruct this * template loader to throw away its current state and start afresh. */ public void resetState(); } libfreemarker-java-2.3.19.orig/src/freemarker/cache/MultiTemplateLoader.java0000644000175000017500000001644211723544471026402 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.IOException; import java.io.Reader; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * A {@link TemplateLoader} that uses a set of other loaders to load the templates. * On every request, loaders are queried in the order of their appearance in the * array of loaders that this Loader owns. If a request for some template name * was already satisfied in the past by one of the loaders, that Loader is queried * first (a soft affinity). * This class is NOT thread-safe. If it is accessed from multiple * threads concurrently, proper synchronization must be provided by the callers. * Note that {@link TemplateCache}, the natural user of this class provides the * necessary synchronizations when it uses the class. * @author Attila Szegedi, szegedia at freemail dot hu * @version $Id: MultiTemplateLoader.java,v 1.12.2.2 2007/04/04 07:51:16 szegedia Exp $ */ public class MultiTemplateLoader implements StatefulTemplateLoader { private final TemplateLoader[] loaders; private final Map lastLoaderForName = Collections.synchronizedMap(new HashMap()); /** * Creates a new multi template Loader that will use the specified loaders. * @param loaders the loaders that are used to load templates. */ public MultiTemplateLoader(TemplateLoader[] loaders) { this.loaders = (TemplateLoader[])loaders.clone(); } public Object findTemplateSource(String name) throws IOException { // Use soft affinity - give the loader that last found this // resource a chance to find it again first. TemplateLoader lastLoader = (TemplateLoader)lastLoaderForName.get(name); if(lastLoader != null) { Object source = lastLoader.findTemplateSource(name); if(source != null) { return new MultiSource(source, lastLoader); } } // If there is no affine loader, or it could not find the resource // again, try all loaders in order of appearance. If any manages // to find the resource, then associate it as the new affine loader // for this resource. for(int i = 0; i < loaders.length; ++i) { TemplateLoader loader = loaders[i]; Object source = loader.findTemplateSource(name); if(source != null) { lastLoaderForName.put(name, loader); return new MultiSource(source, loader); } } lastLoaderForName.remove(name); // Resource not found return null; } public long getLastModified(Object templateSource) { return ((MultiSource)templateSource).getLastModified(); } public Reader getReader(Object templateSource, String encoding) throws IOException { return ((MultiSource)templateSource).getReader(encoding); } public void closeTemplateSource(Object templateSource) throws IOException { ((MultiSource)templateSource).close(); } public void resetState() { lastLoaderForName.clear(); for (int i = 0; i < loaders.length; i++) { TemplateLoader loader = loaders[i]; if(loader instanceof StatefulTemplateLoader) { ((StatefulTemplateLoader)loader).resetState(); } } } /** * Represents a template source bound to a specific template loader. It * serves as the complete template source descriptor used by the * MultiTemplateLoader class. */ private static final class MultiSource { private final Object source; private final TemplateLoader loader; MultiSource(Object source, TemplateLoader loader) { this.source = source; this.loader = loader; } long getLastModified() { return loader.getLastModified(source); } Reader getReader(String encoding) throws IOException { return loader.getReader(source, encoding); } void close() throws IOException { loader.closeTemplateSource(source); } public boolean equals(Object o) { if(o instanceof MultiSource) { MultiSource m = (MultiSource)o; return m.loader.equals(loader) && m.source.equals(source); } return false; } public int hashCode() { return loader.hashCode() + 31 * source.hashCode(); } public String toString() { return source.toString(); } } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/ClassTemplateLoader.java0000644000175000017500000001677311723544471026364 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.net.URL; /** * A {@link TemplateLoader} that uses streams reachable through * {@link Class#getResourceAsStream(String)} as its source of templates. * @author Attila Szegedi, szegedia at freemail dot hu * @version $Id: ClassTemplateLoader.java,v 1.9.2.3 2005/10/10 21:28:46 ddekany Exp $ */ public class ClassTemplateLoader extends URLTemplateLoader { private Class loaderClass; private String path; /** * Creates a template loader that will use the {@link Class#getResource(String)} * method of its own class to load the resources, and "/" as base path. * This means that that template paths will be resolved relatvively the root package * of the class hierarchy, so you hardly ever should use this constructor, rather do * something like this:
* {@link #ClassTemplateLoader(Class, String) * new ClassTemplateLoader(com.example.myapplication.SomeClass.class, "templates")} * *

If you extend this class, then the extending class will be used to load * the resources. * *

Warning: this constructor was malfunctioned prior FreeMarker 2.3.4 * -- please update FreeMarker if needed. * * @deprecated confusing constructor, and seldom useful; * use {@link #ClassTemplateLoader(Class, String)} instead. */ public ClassTemplateLoader() { setFields(this.getClass(), "/"); } /** * Creates a template loader that will use the {@link Class#getResource(String)} * method of the specified class to load the resources, and "" as base * path. This means that template paths will be resolved relatively to the class * location, that is, relatively to the directory (package) of the class. * * @param loaderClass the class whose * {@link Class#getResource(String)} will be used to load the templates. * * @deprecated it is confusing that the base path is ""; * use {@link #ClassTemplateLoader(Class, String)} instead. */ public ClassTemplateLoader(Class loaderClass) { setFields(loaderClass, ""); } /** * Creates a template loader that will use the {@link Class#getResource(String)} method * of the specified class to load the resources, and the specified base path (absolute or relative). * *

Examples: *

    *
  • Relative base path (will load from the * com.example.myapplication.templates package):
    * new ClassTemplateLoader(
    * com.example.myapplication.SomeClass.class,
    * "templates")
    *
  • Absolute base path:
    * new ClassTemplateLoader(
    * somepackage.SomeClass.class,
    * "/com/example/myapplication/templates")
    *
* * @param loaderClass the class whose {@link Class#getResource(String)} method will be used * to load the templates. Be sure that you chose a class whose defining class-loader * sees the templates. This parameter can't be null. * @param path the base path to template resources. * A path that doesn't start with a slash (/) is relative to the * path (package) of the specified class. A path that starts with a slash * is an absolute path starting from the root of the package hierarchy. Path * components should be separated by forward slashes independently of the * separator character used by the underlying operating system. * This parameter can't be null. */ public ClassTemplateLoader(Class loaderClass, String path) { setFields(loaderClass, path); } protected URL getURL(String name) { String fullPath = path + name; // Block java.net.URLClassLoader exploits: if (path.equals("/") && !isSchemeless(fullPath)) { return null; } return loaderClass.getResource(fullPath); } private static boolean isSchemeless(String fullPath) { int i = 0; int ln = fullPath.length(); // Skip a single initial /, as things like "/file:/..." might work: if (i < ln && fullPath.charAt(i) == '/') i++; // Check if there's no ":" earlier than a '/', as the URLClassLoader // could interpret that as an URL scheme: while (i < ln) { char c = fullPath.charAt(i); if (c == '/') return true; if (c == ':') return false; i++; } return true; } private void setFields(Class loaderClass, String path) { if(loaderClass == null) { throw new IllegalArgumentException("loaderClass == null"); } if(path == null) { throw new IllegalArgumentException("path == null"); } this.loaderClass = loaderClass; this.path = canonicalizePrefix(path); } }libfreemarker-java-2.3.19.orig/src/freemarker/cache/FileTemplateLoader.java0000644000175000017500000002216511723544471026166 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import freemarker.template.utility.SecurityUtilities; /** * A {@link TemplateLoader} that uses files in a specified directory as the * source of templates. If contains security checks that will prevent it * serving templates outside the template directory (like <include /etc/passwd>. * It compares canonical paths for this, so templates that are symbolically * linked into the template directory from outside of it won't work either. * @author Attila Szegedi, szegedia at freemail dot hu * @version $Id: FileTemplateLoader.java,v 1.26 2004/03/29 08:06:22 szegedia Exp $ */ public class FileTemplateLoader implements TemplateLoader { private static final boolean SEP_IS_SLASH = File.separatorChar == '/'; public final File baseDir; private final String canonicalPath; /** * Creates a new file template cache that will use the current directory * (the value of the system property user.dir as the base * directory for loading templates. It will not allow access to template * files that are accessible through symlinks that point outside the * base directory. */ public FileTemplateLoader() throws IOException { this(new File(SecurityUtilities.getSystemProperty("user.dir"))); } /** * Creates a new file template loader that will use the specified directory * as the base directory for loading templates. It will not allow access to * template files that are accessible through symlinks that point outside * the base directory. * @param baseDir the base directory for loading templates */ public FileTemplateLoader(final File baseDir) throws IOException { this(baseDir, false); } /** * Creates a new file template loader that will use the specified directory * as the base directory for loading templates. * @param baseDir the base directory for loading templates * @param allowLinking if true, it will allow */ public FileTemplateLoader(final File baseDir, final boolean allowLinking) throws IOException { try { Object[] retval = (Object[]) AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { if (!baseDir.exists()) { throw new FileNotFoundException(baseDir + " does not exist."); } if (!baseDir.isDirectory()) { throw new IOException(baseDir + " is not a directory."); } Object[] retval = new Object[2]; if(allowLinking) { retval[0] = baseDir; retval[1] = null; } else { retval[0] = baseDir.getCanonicalFile(); String basePath = ((File) retval[0]).getPath(); // Most canonical paths don't end with File.separator, // but some does. Like, "C:\" VS "C:\templates". if (!basePath.endsWith(File.separator)) { basePath += File.separatorChar; } retval[1] = basePath; } return retval; } }); this.baseDir = (File) retval[0]; this.canonicalPath = (String) retval[1]; } catch(PrivilegedActionException e) { throw (IOException)e.getException(); } } public Object findTemplateSource(final String name) throws IOException { try { return AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { File source = new File(baseDir, SEP_IS_SLASH ? name : name.replace('/', File.separatorChar)); if(!source.isFile()) { return null; } // Security check for inadvertently returning something // outside the template directory when linking is not // allowed. if(canonicalPath != null) { String normalized = source.getCanonicalPath(); if (!normalized.startsWith(canonicalPath)) { throw new SecurityException(source.getAbsolutePath() + " resolves to " + normalized + " which " + " doesn't start with " + canonicalPath); } } return source; } }); } catch(PrivilegedActionException e) { throw (IOException)e.getException(); } } public long getLastModified(final Object templateSource) { return ((Long)(AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new Long(((File)templateSource).lastModified()); } }))).longValue(); } public Reader getReader(final Object templateSource, final String encoding) throws IOException { try { return (Reader)AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { if (!(templateSource instanceof File)) { throw new IllegalArgumentException( "templateSource is a: " + templateSource.getClass().getName()); } return new InputStreamReader(new FileInputStream( (File)templateSource), encoding); } }); } catch(PrivilegedActionException e) { throw (IOException)e.getException(); } } public void closeTemplateSource(Object templateSource) { // Do nothing. } }libfreemarker-java-2.3.19.orig/src/freemarker/cache/NullCacheStorage.java0000644000175000017500000000622311723544470025643 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.util.Map; /** * A cache storage that doesn't store anything. Use this if you * don't want caching. * * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) */ public class NullCacheStorage implements ConcurrentCacheStorage { public boolean isConcurrent() { return true; } public Object get(Object key) { return null; } public void put(Object key, Object value) { // do nothing } public void remove(Object key) { // do nothing } public void clear() { // do nothing } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/ConcurrentCacheStorage.java0000644000175000017500000000115011723544470027045 0ustar ebourgebourgpackage freemarker.cache; /** * An optional interface for cache storage that knows whether it can be * concurrently accessible without synchronization. * @author Attila Szegedi * @version $Id: $ */ public interface ConcurrentCacheStorage extends CacheStorage { /** * Returns true if this instance of cache storage is concurrently * accessible from multiple threads without synchronization. * @return true if this instance of cache storage is concurrently * accessible from multiple threads without synchronization. */ public boolean isConcurrent(); } libfreemarker-java-2.3.19.orig/src/freemarker/cache/TemplateCache.java0000644000175000017500000007556411723544472025177 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.IOException; import java.io.Reader; import java.io.Serializable; import java.io.StringWriter; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import freemarker.core.Environment; import freemarker.log.Logger; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.utility.StringUtil; import freemarker.template.utility.UndeclaredThrowableException; /** * A class that performs caching and on-demand loading of the templates. * The actual loading is delegated to a {@link TemplateLoader}. Also, * various constructors provide you with convenient caches with predefined * behavior. Typically you don't use this class directly - in normal * circumstances it is hidden behind a {@link Configuration}. However, * the {@link CacheStorage} it uses can be set with * {@link freemarker.template.Configuration#setCacheStorage(CacheStorage)} * * @author Attila Szegedi */ public class TemplateCache { private static final String ASTERISKSTR = "*"; private static final String LOCALE_SEPARATOR = "_"; private static final char ASTERISK = '*'; private static final String CURRENT_DIR_PATH_PREFIX = "./"; private static final String CURRENT_DIR_PATH = "/./"; private static final String PARENT_DIR_PATH_PREFIX = "../"; private static final String PARENT_DIR_PATH = "/../"; private static final char SLASH = '/'; private static final Logger logger = Logger.getLogger("freemarker.cache"); private final TemplateLoader templateLoader; /** Here we keep our cached templates */ private final CacheStorage storage; private final boolean isStorageConcurrent; /** The default refresh delay in milliseconds. */ private long delay = 5000; /** Specifies if localized template lookup is enabled or not */ private boolean localizedLookup = true; private Configuration config; /** * Returns a template cache that will first try to load a template from * the file system relative to the current user directory (i.e. the value * of the system property user.dir), then from the classpath. * This default template cache suits many applications. */ public TemplateCache() { this(createDefaultTemplateLoader()); } private static TemplateLoader createDefaultTemplateLoader() { try { return new FileTemplateLoader(); } catch(Exception e) { logger.warn("Could not create a file template loader for current directory", e); return null; } } /** * Creates a new template cache with a custom template loader that is used * to load the templates. * @param loader the template loader to use. */ public TemplateCache(TemplateLoader loader) { this(loader, new SoftCacheStorage()); } /** * Creates a new template cache with a custom template loader that is used * to load the templates. * @param loader the template loader to use. */ public TemplateCache(TemplateLoader loader, CacheStorage storage) { this.templateLoader = loader; this.storage = storage; if(storage == null) { throw new IllegalArgumentException("storage == null"); } isStorageConcurrent = storage instanceof ConcurrentCacheStorage && ((ConcurrentCacheStorage)storage).isConcurrent(); } /** * Sets the configuration object to which this cache belongs. This * method is called by the configuration itself to establish the * relation, and should not be called by users. */ public void setConfiguration(Configuration config) { this.config = config; clear(); } public TemplateLoader getTemplateLoader() { return templateLoader; } public CacheStorage getCacheStorage() { return storage; } /** * Loads a template with the given name, in the specified locale and * using the specified character encoding. * * @param name the name of the template. Can't be null. The exact syntax of the name * is interpreted by the underlying {@link TemplateLoader}, but the * cache makes some assumptions. First, the name is expected to be * a hierarchical path, with path components separated by a slash * character (not with backslash!). The path (the name) must not begin with slash; * the path is always relative to the "template root directory". * Then, the .. and . path metaelements will be resolved. * For example, if the name is a/../b/./c.ftl, then it will be * simplified to b/c.ftl. The rules regarding this are same as with conventional * UN*X paths. The path must not reach outside the template root directory, that is, * it can't be something like "../templates/my.ftl" (not even if the pervious path * happens to be equivalent with "/my.ftl"). * Further, the path is allowed to contain at most * one path element whose name is * (asterisk). This path metaelement triggers the * acquisition mechanism. If the template is not found in * the location described by the concatenation of the path left to the * asterisk (called base path) and the part to the right of the asterisk * (called resource path), the cache will attempt to remove the rightmost * path component from the base path ("go up one directory") and concatenate * that with the resource path. The process is repeated until either a * template is found, or the base path is completely exhausted. * * @param locale the requested locale of the template. Can't be null. * Assuming you have specified en_US as the locale and * myTemplate.html as the name of the template, the cache will * first try to retrieve myTemplate_en_US.html, then * myTemplate.html_en.html, and finally * myTemplate.html. * * @param encoding the character encoding used to interpret the template * source bytes. Can't be null. * * @param parse if true, the loaded template is parsed and interpreted * as a regular FreeMarker template. If false, the loaded template is * treated as an unparsed block of text. * * @return the loaded template, or null if the template is not found. */ public Template getTemplate(String name, Locale locale, String encoding, boolean parse) throws IOException { if (name == null) { throw new IllegalArgumentException("Argument \"name\" can't be null"); } if (locale == null) { throw new IllegalArgumentException("Argument \"locale\" can't be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument \"encoding\" can't be null"); } name = normalizeName(name); if(name == null) { return null; } Template result = null; if (templateLoader != null) { result = getTemplate(templateLoader, name, locale, encoding, parse); } return result; } private Template getTemplate(TemplateLoader loader, String name, Locale locale, String encoding, boolean parse) throws IOException { boolean debug = logger.isDebugEnabled(); String debugName = debug ? buildDebugName(name, locale, encoding, parse) : null; TemplateKey tk = new TemplateKey(name, locale, encoding, parse); CachedTemplate cachedTemplate; if(isStorageConcurrent) { cachedTemplate = (CachedTemplate)storage.get(tk); } else { synchronized(storage) { cachedTemplate = (CachedTemplate)storage.get(tk); } } long now = System.currentTimeMillis(); long lastModified = -1L; Object newlyFoundSource = null; boolean rethrown = false; try { if (cachedTemplate != null) { // If we're within the refresh delay, return the cached copy if (now - cachedTemplate.lastChecked < delay) { if(debug) { logger.debug(debugName + " cached copy not yet stale; using cached."); } // Can be null, indicating a cached negative lookup Object t = cachedTemplate.templateOrException; if(t instanceof Template || t == null) { return (Template)t; } else if(t instanceof RuntimeException) { throwLoadFailedException((RuntimeException)t); } else if(t instanceof IOException) { rethrown = true; throwLoadFailedException((IOException)t); } throw new RuntimeException("t is " + t.getClass().getName()); } // Clone as the instance bound to the map should be treated as // immutable to ensure proper concurrent semantics cachedTemplate = cachedTemplate.cloneCachedTemplate(); // Update the last-checked flag cachedTemplate.lastChecked = now; // Find the template source newlyFoundSource = findTemplateSource(name, locale); // Template source was removed if (newlyFoundSource == null) { if(debug) { logger.debug(debugName + " no source found."); } storeNegativeLookup(tk, cachedTemplate, null); return null; } // If the source didn't change and its last modified date // also didn't change, return the cached version. lastModified = loader.getLastModified(newlyFoundSource); boolean lastModifiedNotChanged = lastModified == cachedTemplate.lastModified; boolean sourceEquals = newlyFoundSource.equals(cachedTemplate.source); if(lastModifiedNotChanged && sourceEquals) { if(debug) { logger.debug(debugName + " using cached since " + newlyFoundSource + " didn't change."); } storeCached(tk, cachedTemplate); return (Template)cachedTemplate.templateOrException; } else { if(debug && !sourceEquals) { logger.debug("Updating source, info for cause: " + "sourceEquals=" + sourceEquals + ", newlyFoundSource=" + StringUtil.jQuoteNoXSS(newlyFoundSource) + ", cachedTemplate.source=" + StringUtil.jQuoteNoXSS(cachedTemplate.source)); } if(debug && !lastModifiedNotChanged) { logger.debug("Updating source, info for cause: " + "lastModifiedNotChanged=" + lastModifiedNotChanged + ", cache lastModified=" + cachedTemplate.lastModified + " != file lastModified=" + lastModified); } // Update the source cachedTemplate.source = newlyFoundSource; } } else { if(debug) { logger.debug("Could not find template in cache, " + "creating new one; id=[" + StringUtil.jQuoteNoXSS(tk.name) + "[" + StringUtil.jQuoteNoXSS(tk.locale) + "," + tk.encoding + (tk.parse ? ",parsed] " : ",unparsed] ") + "]"); } // Construct a new CachedTemplate entry. Note we set the // cachedTemplate.lastModified to Long.MIN_VALUE. This is // a flag that signs it has to be explicitly queried later on. cachedTemplate = new CachedTemplate(); cachedTemplate.lastChecked = now; newlyFoundSource = findTemplateSource(name, locale); if (newlyFoundSource == null) { storeNegativeLookup(tk, cachedTemplate, null); return null; } cachedTemplate.source = newlyFoundSource; cachedTemplate.lastModified = lastModified = Long.MIN_VALUE; } if(debug) { logger.debug("Compiling FreeMarker template " + debugName + " from " + StringUtil.jQuoteNoXSS(newlyFoundSource)); } // If we get here, then we need to (re)load the template Object source = cachedTemplate.source; Template t = loadTemplate(loader, name, locale, encoding, parse, source); cachedTemplate.templateOrException = t; cachedTemplate.lastModified = lastModified == Long.MIN_VALUE ? loader.getLastModified(source) : lastModified; storeCached(tk, cachedTemplate); return t; } catch(RuntimeException e) { storeNegativeLookup(tk, cachedTemplate, e); throw e; } catch(IOException e) { if(!rethrown) { storeNegativeLookup(tk, cachedTemplate, e); } throw e; } finally { if(newlyFoundSource != null) { loader.closeTemplateSource(newlyFoundSource); } } } private static final Method INIT_CAUSE = getInitCauseMethod(); private static final Method getInitCauseMethod() { try { return Throwable.class.getMethod("initCause", new Class[] { Throwable.class }); } catch(NoSuchMethodException e) { return null; } } private void throwLoadFailedException(Exception e) throws IOException { IOException ioe; if(INIT_CAUSE != null) { ioe = new IOException("There was an error loading the " + "template on an earlier attempt; it is attached as a cause"); try { INIT_CAUSE.invoke(ioe, new Object[] { e }); } catch(RuntimeException ex) { throw ex; } catch(Exception ex) { throw new UndeclaredThrowableException(ex); } } else { ioe = new IOException("There was an error loading the " + "template on an earlier attempt: " + e.getClass().getName() + ": " + e.getMessage()); } throw ioe; } private void storeNegativeLookup(TemplateKey tk, CachedTemplate cachedTemplate, Exception e) { cachedTemplate.templateOrException = e; cachedTemplate.source = null; cachedTemplate.lastModified = 0L; storeCached(tk, cachedTemplate); } private void storeCached(TemplateKey tk, CachedTemplate cachedTemplate) { if(isStorageConcurrent) { storage.put(tk, cachedTemplate); } else { synchronized(storage) { storage.put(tk, cachedTemplate); } } } private Template loadTemplate(TemplateLoader loader, String name, Locale locale, String encoding, boolean parse, Object source) throws IOException { Template template; Reader reader = loader.getReader(source, encoding); try { if(parse) { try { template = new Template(name, reader, config, encoding); } catch (Template.WrongEncodingException wee) { encoding = wee.specifiedEncoding; reader = loader.getReader(source, encoding); template = new Template(name, reader, config, encoding); } template.setLocale(locale); } else { // Read the contents into a StringWriter, then construct a single-textblock // template from it. StringWriter sw = new StringWriter(); char[] buf = new char[4096]; for(;;) { int charsRead = reader.read(buf); if (charsRead > 0) { sw.write(buf, 0, charsRead); } else if(charsRead == -1) { break; } } template = Template.getPlainTextTemplate(name, sw.toString(), config); template.setLocale(locale); } template.setEncoding(encoding); } finally { reader.close(); } return template; } /** * Gets the delay in milliseconds between checking for newer versions of a * template source. * @return the current value of the delay */ public synchronized long getDelay() { return delay; } /** * Sets the delay in milliseconds between checking for newer versions of a * template sources. * @param delay the new value of the delay */ public synchronized void setDelay(long delay) { this.delay = delay; } /** * Returns if localized template lookup is enabled or not. */ public synchronized boolean getLocalizedLookup() { return localizedLookup; } /** * Setis if localized template lookup is enabled or not. */ public synchronized void setLocalizedLookup(boolean localizedLookup) { this.localizedLookup = localizedLookup; } /** * Removes all entries from the cache, forcing reloading of templates * on subsequent {@link #getTemplate(String, Locale, String, boolean)} * calls. If the configured template loader is * {@link StatefulTemplateLoader stateful}, then its * {@link StatefulTemplateLoader#resetState()} method is invoked as well. */ public void clear() { synchronized (storage) { storage.clear(); if(templateLoader instanceof StatefulTemplateLoader) { ((StatefulTemplateLoader)templateLoader).resetState(); } } } /** * Removes an entry from the cache, hence forcing the re-loading of it when * it's next time requested. It doesn't delete the template file itself. * This is to give the application finer control over cache updating than * {@link #setDelay(long)} alone does. * * For the meaning of the parameters, see * {@link #getTemplate(String, Locale, String, boolean)}. */ public void removeTemplate( String name, Locale locale, String encoding, boolean parse) throws IOException { if (name == null) { throw new IllegalArgumentException("Argument \"name\" can't be null"); } if (locale == null) { throw new IllegalArgumentException("Argument \"locale\" can't be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument \"encoding\" can't be null"); } name = normalizeName(name); if(name != null && templateLoader != null) { boolean debug = logger.isDebugEnabled(); String debugName = debug ? buildDebugName(name, locale, encoding, parse) : null; TemplateKey tk = new TemplateKey(name, locale, encoding, parse); if(isStorageConcurrent) { storage.remove(tk); } else { synchronized(storage) { storage.remove(tk); } } logger.debug(debugName + " was removed from the cache, if it was there"); } } private String buildDebugName(String name, Locale locale, String encoding, boolean parse) { return StringUtil.jQuoteNoXSS(name) + "[" + StringUtil.jQuoteNoXSS(locale) + "," + encoding + (parse ? ",parsed] " : ",unparsed]"); } public static String getFullTemplatePath(Environment env, String parentTemplateDir, String templateNameString) { if (!env.isClassicCompatible()) { if (templateNameString.indexOf("://") >0) { ; } else if (templateNameString.length() > 0 && templateNameString.charAt(0) == '/') { int protIndex = parentTemplateDir.indexOf("://"); if (protIndex >0) { templateNameString = parentTemplateDir.substring(0, protIndex + 2) + templateNameString; } else { templateNameString = templateNameString.substring(1); } } else { templateNameString = parentTemplateDir + templateNameString; } } return templateNameString; } private Object findTemplateSource(String name, Locale locale) throws IOException { if (localizedLookup) { int lastDot = name.lastIndexOf('.'); String prefix = lastDot == -1 ? name : name.substring(0, lastDot); String suffix = lastDot == -1 ? "" : name.substring(lastDot); String localeName = LOCALE_SEPARATOR + locale.toString(); StringBuffer buf = new StringBuffer(name.length() + localeName.length()); buf.append(prefix); for (;;) { buf.setLength(prefix.length()); String path = buf.append(localeName).append(suffix).toString(); Object templateSource = acquireTemplateSource(path); if (templateSource != null) { return templateSource; } int lastUnderscore = localeName.lastIndexOf('_'); if (lastUnderscore == -1) break; localeName = localeName.substring(0, lastUnderscore); } return null; } else { return acquireTemplateSource(name); } } private Object acquireTemplateSource(String path) throws IOException { int asterisk = path.indexOf(ASTERISK); // Shortcut in case there is no acquisition if(asterisk == -1) { return templateLoader.findTemplateSource(path); } StringTokenizer tok = new StringTokenizer(path, "/"); int lastAsterisk = -1; List tokpath = new ArrayList(); while(tok.hasMoreTokens()) { String pathToken = tok.nextToken(); if(pathToken.equals(ASTERISKSTR)) { if(lastAsterisk != -1) { tokpath.remove(lastAsterisk); } lastAsterisk = tokpath.size(); } tokpath.add(pathToken); } String basePath = concatPath(tokpath, 0, lastAsterisk); String resourcePath = concatPath(tokpath, lastAsterisk + 1, tokpath.size()); if(resourcePath.endsWith("/")) { resourcePath = resourcePath.substring(0, resourcePath.length() - 1); } StringBuffer buf = new StringBuffer(path.length()).append(basePath); int l = basePath.length(); boolean debug = logger.isDebugEnabled(); for(;;) { String fullPath = buf.append(resourcePath).toString(); if(debug) { logger.debug("Trying to find template source " + StringUtil.jQuoteNoXSS(fullPath)); } Object templateSource = templateLoader.findTemplateSource(fullPath); if(templateSource != null) { return templateSource; } if(l == 0) { return null; } l = basePath.lastIndexOf(SLASH, l - 2) + 1; buf.setLength(l); } } private String concatPath(List path, int from, int to) { StringBuffer buf = new StringBuffer((to - from) * 16); for(int i = from; i < to; ++i) { buf.append(path.get(i)).append('/'); } return buf.toString(); } private static String normalizeName(String name) { // Disallow 0 for security reasons. if (name.indexOf(0) != -1) return null; for(;;) { int parentDirPathLoc = name.indexOf(PARENT_DIR_PATH); if(parentDirPathLoc == 0) { // If it starts with /../, then it reaches outside the template // root. return null; } if(parentDirPathLoc == -1) { if(name.startsWith(PARENT_DIR_PATH_PREFIX)) { // Another attempt to reach out of template root. return null; } break; } int previousSlashLoc = name.lastIndexOf(SLASH, parentDirPathLoc - 1); name = name.substring(0, previousSlashLoc + 1) + name.substring(parentDirPathLoc + PARENT_DIR_PATH.length()); } for(;;) { int currentDirPathLoc = name.indexOf(CURRENT_DIR_PATH); if(currentDirPathLoc == -1) { if(name.startsWith(CURRENT_DIR_PATH_PREFIX)) { name = name.substring(CURRENT_DIR_PATH_PREFIX.length()); } break; } name = name.substring(0, currentDirPathLoc) + name.substring(currentDirPathLoc + CURRENT_DIR_PATH.length() - 1); } // Editing can leave us with a leading slash; strip it. if(name.length() > 1 && name.charAt(0) == SLASH) { name = name.substring(1); } return name; } /** * This class holds a (name, locale) pair and is used as the key in * the cached templates map. */ private static final class TemplateKey { private final String name; private final Locale locale; private final String encoding; private final boolean parse; TemplateKey(String name, Locale locale, String encoding, boolean parse) { this.name = name; this.locale = locale; this.encoding = encoding; this.parse = parse; } public boolean equals(Object o) { if (o instanceof TemplateKey) { TemplateKey tk = (TemplateKey)o; return parse == tk.parse && name.equals(tk.name) && locale.equals(tk.locale) && encoding.equals(tk.encoding); } return false; } public int hashCode() { return name.hashCode() ^ locale.hashCode() ^ encoding.hashCode() ^ (parse ? Boolean.FALSE : Boolean.TRUE).hashCode(); } } /** * This class holds the cached template and associated information * (the source object, and the last-checked and last-modified timestamps). * It is used as the value in the cached templates map. Note: this class * is Serializable to allow custom 3rd party CacheStorage implementations * to serialize/replicate them (see tracker issue #1926150); FreeMarker * code itself doesn't rely on its serializability. */ private static final class CachedTemplate implements Cloneable, Serializable { private static final long serialVersionUID = 1L; Object templateOrException; Object source; long lastChecked; long lastModified; public CachedTemplate cloneCachedTemplate() { try { return (CachedTemplate)super.clone(); } catch(CloneNotSupportedException e) { throw new UndeclaredThrowableException(e); } } } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/URLTemplateLoader.java0000644000175000017500000001165011723544471025746 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.URL; /** * This is an abstract template loader that can load templates whose * location can be described by an URL. Subclasses only need to override * the {@link #getURL(String)} method. Both {@link ClassTemplateLoader} and * {@link WebappTemplateLoader} are (quite trivial) subclasses of this class. * @version $Id: URLTemplateLoader.java,v 1.14 2003/01/29 08:01:17 szegedia Exp $ * @author Attila Szegedi */ public abstract class URLTemplateLoader implements TemplateLoader { public Object findTemplateSource(String name) throws IOException { URL url = getURL(name); return url == null ? null : new URLTemplateSource(url); } /** * Given a template name (plus potential locale decorations) retrieves * an URL that points the template source. * @param name the name of the sought template, including the locale * decorations. * @return an URL that points to the template source, or null if it can * determine that the template source does not exist. */ protected abstract URL getURL(String name); public long getLastModified(Object templateSource) { return ((URLTemplateSource) templateSource).lastModified(); } public Reader getReader(Object templateSource, String encoding) throws IOException { return new InputStreamReader( ((URLTemplateSource) templateSource).getInputStream(), encoding); } public void closeTemplateSource(Object templateSource) throws IOException { ((URLTemplateSource) templateSource).close(); } /** * Can be used by subclasses to canonicalize URL path prefixes. * @param prefix the path prefix to canonicalize * @return the canonicalized prefix. All backslashes are replaced with * forward slashes, and a trailing slash is appended if the original * prefix wasn't empty and didn't already end with a slash. */ protected static String canonicalizePrefix(String prefix) { // make it foolproof prefix = prefix.replace('\\', '/'); // ensure there's a trailing slash if (prefix.length() > 0 && !prefix.endsWith("/")) { prefix += "/"; } return prefix; } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/WebappTemplateLoader.java0000644000175000017500000001611311723544470026520 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.MalformedURLException; import java.net.URL; import javax.servlet.ServletContext; import freemarker.log.Logger; import freemarker.template.utility.StringUtil; /** * A {@link TemplateLoader} that uses streams reachable through * {@link ServletContext#getResource(String)} as its source of templates. * @version $Id: WebappTemplateLoader.java,v 1.10 2003/01/29 08:01:18 szegedia Exp $ * @author Attila Szegedi */ public class WebappTemplateLoader implements TemplateLoader { private static final Logger logger = Logger.getLogger("freemarker.cache"); private final ServletContext servletContext; private final String path; /** * Creates a resource template cache that will use the specified servlet * context to load the resources. It will use the base path of * "/" meaning templates will be resolved relative to the * servlet context root location. * @param servletContext the servlet context whose * {@link ServletContext#getResource(String)} will be used to load the * templates. */ public WebappTemplateLoader(ServletContext servletContext) { this(servletContext, "/"); } /** * Creates a template loader that will use the specified servlet * context to load the resources. It will use the specified base path. * The is interpreted as relative to the current context root (does not mater * if you start it with "/" or not). Path components * should be separated by forward slashes independently of the separator * character used by the underlying operating system. * @param servletContext the servlet context whose * {@link ServletContext#getResource(String)} will be used to load the * templates. * @param path the base path to template resources. */ public WebappTemplateLoader(ServletContext servletContext, String path) { if(servletContext == null) { throw new IllegalArgumentException("servletContext == null"); } if(path == null) { throw new IllegalArgumentException("path == null"); } path = path.replace('\\', '/'); if(!path.endsWith("/")) { path += "/"; } if (!path.startsWith("/")) { path = "/" + path; } this.path = path; this.servletContext = servletContext; } public Object findTemplateSource(String name) throws IOException { String fullPath = path + name; // First try to open as plain file (to bypass servlet container resource caches). try { String realPath = servletContext.getRealPath(fullPath); if (realPath != null) { File file = new File(realPath); if(!file.isFile()) { return null; } if(file.canRead()) { return file; } } } catch (SecurityException e) { ;// ignore } // If it fails, try to open it with servletContext.getResource. URL url = null; try { url = servletContext.getResource(fullPath); } catch(MalformedURLException e) { logger.warn("Could not retrieve resource " + StringUtil.jQuoteNoXSS(fullPath), e); return null; } return url == null ? null : new URLTemplateSource(url); } public long getLastModified(Object templateSource) { if (templateSource instanceof File) { return ((File) templateSource).lastModified(); } else { return ((URLTemplateSource) templateSource).lastModified(); } } public Reader getReader(Object templateSource, String encoding) throws IOException { if (templateSource instanceof File) { return new InputStreamReader( new FileInputStream((File) templateSource), encoding); } else { return new InputStreamReader( ((URLTemplateSource) templateSource).getInputStream(), encoding); } } public void closeTemplateSource(Object templateSource) throws IOException { if (templateSource instanceof File) { // Do nothing. } else { ((URLTemplateSource) templateSource).close(); } } }libfreemarker-java-2.3.19.orig/src/freemarker/cache/StrongCacheStorage.java0000644000175000017500000000725211723544467026216 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.util.Map; /** * Strong cache storage is a cache storage that simply wraps a {@link Map}. * It holds a strong reference to all objects it was passed, therefore prevents * the cache from being purged during garbage collection. * This class is thread-safe to the extent that its underlying map is. The * default implementation uses a concurrent map on Java 5 and above, so it is * thread-safe in that case. * * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) * * @author Attila Szegedi */ public class StrongCacheStorage implements ConcurrentCacheStorage { private final Map map = ConcurrentMapFactory.createMap(); /** * Returns true if the underlying Map is a {@code ConcurrentMap}. */ public boolean isConcurrent() { return ConcurrentMapFactory.isConcurrent(map); } public Object get(Object key) { return map.get(key); } public void put(Object key, Object value) { map.put(key, value); } public void remove(Object key) { map.remove(key); } public void clear() { map.clear(); } } libfreemarker-java-2.3.19.orig/src/freemarker/cache/TemplateLoader.java0000644000175000017500000001737711723544470025376 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.cache; import java.io.IOException; import java.io.Reader; /** * A template loader is an object that can find the source stream for a * template, can retrieve its time of last modification as well as the stream * itself. A template loader is plugged into the {@link TemplateCache} to * provide concrete loading of the templates. * The implementations can be coded in a non-threadsafe manner as the natural * user of the template loader, {@link TemplateCache} does the necessary * synchronization. * @author Attila Szegedi, szegedia at freemail dot hu * @version $Id: TemplateLoader.java,v 1.18 2004/03/01 01:13:30 ddekany Exp $ */ public interface TemplateLoader { /** * Finds the object that acts as the source of the template with the * given name. This method is called by the TemplateCache when a template * is requested, before calling either {@link #getLastModified(Object)} or * {@link #getReader(Object, String)}. * * @param name the name of the template, already localized and normalized by * the {@link freemarker.cache.TemplateCache cache}. * It is completely up to the loader implementation to interpret * the name, however it should expect to receive hierarchical paths where * path components are separated by a slash (not backslash). Backslashes * (or any other OS specific separator character) are not considered as separators by * FreeMarker, and thus they will not be replaced with slash before passing to this method, * so it is up to the template loader to handle them (say, be throwing and exception that * tells the user that the path (s)he has entered is invalid, as (s)he must use slash -- * typical mistake of Windows users). * The passed names are always considered relative to some loader-defined root * location (often reffered as the "template root direcotry"), and will never start with * a slash, nor will they contain a path component consisting of either a single or a double * dot -- these are all resolved by the template cache before passing the name to the * loader. As a side effect, paths that trivially reach outside template root directory, * such as ../my.ftl, will be rejected by the template cache, so they never * reach the template loader. Note again, that if the path uses backslash as path separator * instead of slash as (the template loader should not accept that), the normalisation will * not properly happen, as FreeMarker (the cache) recognizes only the slashes as separators. * * @return an object representing the template source, which can be * supplied in subsequent calls to {@link #getLastModified(Object)} and * {@link #getReader(Object, String)}. Null must be returned if the source * for the template can not be found (do not throw FileNotFoundException!). * The returned object may will be compared with a cached template source * object for equality, using the equals method. Thus, * objects returned for the same physical source must be equivalent * according to equals method, otherwise template caching * can become very ineffective! */ public Object findTemplateSource(String name) throws IOException; /** * Returns the time of last modification of the specified template source. * This method is called after findTemplateSource(). * @param templateSource an object representing a template source, obtained * through a prior call to {@link #findTemplateSource(String)}. * @return the time of last modification of the specified template source, * or -1 if the time is not known. */ public long getLastModified(Object templateSource); /** * Returns the character stream of a template represented by the specified * template source. This method is called after getLastModified() * if it is determined that a cached copy of the template is unavailable * or stale. * @param templateSource an object representing a template source, obtained * through a prior call to {@link #findTemplateSource(String)}. * @param encoding the character encoding used to translate source bytes * to characters. Some loaders may not have access to the byte * representation of the template stream, and instead directly obtain a * character stream. These loaders will - quite naturally - ignore the * encoding parameter. * @return a reader representing the template character stream. The * framework will call close(). * @throws IOException if an I/O error occurs while accessing the stream. */ public Reader getReader(Object templateSource, String encoding) throws IOException; /** * Closes the template source. This is the last method that is called by * the TemplateCache for a templateSource. The framework guarantees that * this method will be called on every object that is returned from * {@link #findTemplateSource(String)}. * @param templateSource the template source that should be closed. */ public void closeTemplateSource(Object templateSource) throws IOException; } libfreemarker-java-2.3.19.orig/src/freemarker/cache/package.html0000644000175000017500000000066311723544471024101 0ustar ebourgebourg

Contains classes and interfaces that deal with template loading and caching. Beside the actual template cache, it contains loaders that can load template files from the file system, from the classpath, or from a web application context. If you have specific needs, you can plug custom template loaders into the system by implementing the template loader interface.

libfreemarker-java-2.3.19.orig/src/manual/0000755000175000017500000000000012164627123017676 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/manual/docgen.cjson0000644000175000017500000000075011723544471022201 0ustar ebourgebourgolinks: { homepage: "http://freemarker.org/" api: "api/index.html" } internalBookmarks: { "Alphabetical Index": alphaidx "Glossary": gloss "Reference": ref "FAQ": app_faq } externalBookmarks: { "Java API": "api/index.html" "FreeMarker Home": "../index.html" } validation: { programlistingsRequireRole // programlistingsRequireLanguage } generateEclipseTOC // eclipse: { // link_to: "freemarker-toc.xml#ManualLink" // } showXXELogo libfreemarker-java-2.3.19.orig/src/manual/figures/0000755000175000017500000000000012164627123021342 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/manual/figures/model2sketch.png0000644000175000017500000005166111723544471024451 0ustar ebourgebourg‰PNG  IHDRXEëîª+tEXtCreation TimeH 30 dec. 2002 11:58:10 +0100@(8tIMEÒ 8›vø pHYs  ÒÝ~ügAMA± üaúPLTEþþþùóóóóóêèèãããÛÛÛר×ÓÓÓËËËÀÀÀ½Á½ººº³³³¯¯²¨¨¨ßßáCCCkkk£££ÞáÞ [[[“““‚‚‚cccnnqXWW**+ÅÅÈsss›››{{{0//µµºLKL444‹‹‹###<<<––™€"SRSddjˆ‡‡u{uŒ’Œtty¨¤¤¥¥¨Ë»»Ò»»Â¶¶Ì––åXXô##í\\Æ¥¥Øwwì66þëhh´¬¬ÆŠŠâQQû¬ŠŠÎmmë,,DDK¸xxÞEEÊuuìããöµµõffÛ×XX§››éÆÆô††ù88´††µ––ÚªªÕ³³Ü´´Û»»ØÈÈéÚÚõwwú++îPP臇瘘컻õ++ú##ò——÷FFî¹²²Å¼¼ÚÔÔ÷ÖÖøËËöWWêzz.Òccôæææ©©ò§§Ù……¥©¥„„‰T’Ù™™ËÃÃÅ›™ÊžžæHH*?Uª»ªÿßÿÀÜÀ*UU?UÔßÿS]SUU}}¦ªŸª*?**UUª*_UÔߪŸªÀÀÿ¿ª€€*UUŸªU¦Êð*ª*Ÿª*ŸUÔÿÿ*_ªUŸUU¿ªlJ”š”{ƒ{isi2=2","'6'CMCšš bmb4,V,E‰ES§S`¿`;u;&zz„RR\77E$$-++8EEV$E$\¸\l×ltèt€ÿ€|ø|22;KKcYYvvv¿Ñ¬¬å··ô²²í¢¢Ønn’>>S4f4  ‹‹“‰‰¶––ÇffˆZdZSSh„‹„¸¸ÆHUH4Z4L˜LdÇd6C6„õz•ÔjŠèt ¿`Ät:ÝB!ë(â8 ‹„hµ[«§SÒX,ÆÔñÍc2»‡DndB$‹»]›Çc³–Kà? ¢¹]8}|p&.tÎgÐ Î B_b1‚‚­›¤›Îòa¾PIDATxÚìËsG~Ç1ýšA¢Ñ   @‘!‘¢¥Õ-©U¥Ê_6®¤*Ñnª\kŸâÊaË{HÎ._õ'X¶˜˜´,³lP2%J–d½mÉry%?j³ÊÁ›²÷°I*ooUú5ƒñæ@àþ’Ò æÁ‡¿þ¡ûÛ=¡‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘ÑHÊ’¿FFÊB–aË(HáCEJ³3.gk¯/Åh„”KR©´ YFÁ©Dç"ØŽÎÓe$Ȫʶv$^ÖŽ#£&²(µ‰m;št‘È´ÔgXò¥â‹ÿÔ¬1 ™Qk4ØB„`ádš¦§y䔎'çiQ°e© àtõš’ÈõŒš  ±é9‚+ŒXV¦[%N¥ó4§û9JcôYˆêÖ@C–QK_¢4YZ!Œ¡ƒt~ŒDJt#JS69@3.‚š@:©¬!˜™Lߨ¥€x¼OÒ¬ãò°”³žnÍÛ„xŽí¤c6f±4ÆYv*kl#–Q+Y2̳÷#tcª•tJ9Hö4Í“=Bìº566˨¥’” †9Z4)‚‘VNác‡éœ½ÌØ]·†ð¢ÐäXF-T¢sã`ÙEº,ÂçT\Âq:‘œ³±&Rµ†˜’Ш¥¬ JE°}´HSŽ=IçF&&iIãÃÐQ¤ò<–œj^µZž¹tÇ#£6š!Kr#}2z­7gYõkŒŒZÉòª^†j MÖ+áz¡_éáó^*;_H½®ÚÌRþ>oÍhýÆ_ŠêÓb4J°ÂF#§A°-Zá½¾£ w0`œÂ޽÷d°FOá1ïuã§eÀ=…ÇÃd¯© X#¨ðĘmÀ2 \áh„'YƒVë+jµVÖLîéû1 XE̱‰Ò(§=‚huEî8PÔI97{xCt0jŠGFVa ëPv05­˜²¨*(ÍeæhFʺãÄ Qã/TVøYNE1š…Æ#²e€ÿPP±+¹i(G~£œUå À³AU­…#ЛY €:…!+0 XVB»‹biqœÆÿÔsÙQdY§átA@§’ó è‰÷UÎ9@Š`l–ÆÈ-’‰‰/]”‡+bàÐ0°‹€ñ×â|c á¤!+0 X`rNeÐôK<QÆ2ÒŒ;‘Qžpv`8_&V9ñÃ)v4Á@q$’bg8‘=<&elÀ÷É+Ƀü, u$R¬„ )ü変YÁiàÀ²ögàòQ6ñNåŠADÒQ›°”c˜M” rK †¨ƒpŒó%&Ы1áÇe"dQaøåÑ‹2F ßXüó]Fñ™š;Šb.bâ|:UBÈôgLƒ˜Giâ’%R$ !SF\Šdâ4'ÍaFÿÇÔÄ'‚ƒ…]ÑQ‰–—(æ;c—ÿ“ËщÙâ‡SòF‘Ëèr6Çà^7BŒŽ¬H-ÇÆO-Ç]Ìb|Ž‹:DD'—xêŽ&éœXf§]5AH›É-*º»ˆ‹ƒ5?ÈQB(&,¬W:X"¥™á„a¾L­ÅS)×ô” LV”.0—åé +ÆS³œI;‘ô€Â DÂÌ—­d°šø}§$P¢ÌÓd˜d¨ms°T¼TÄ©09ÌWˆÈ‘dÔaœ_Ö`¹d6búŒ¦ÁË‚ÉcËÿí8ÍŽqzé8‘•Y${L‘,¦ûèœÕ„hª,¨ž{bš/Æ ”ؼ(EªÌsÅáÂGè™ ã„8%w.q4n"V`<°B²Ožß!ÆC2qR–W¨ÓrÌË1™~a&ƒ™8’ØYÖ}©Íä`B É^£êˆŒ©ÃÉ"‘!%y>Õ‡Ô€,Qye¿<<¾ L±,ÏÏÓsAœ«úËêOí¶¶4$1 ôèãªû“ÖÉ|+ JV¨Î”/»tªhR}ô$6º •­ûUìzêE·ÓèB°S&`¤A+ä|n…¬ªî;Ú³às½VÅU¨â|ºÏ¨ÞU†1}¸ÊroµŒ…–qE§«nu¨Q/5*±§q ‘ ƒÀªÛÕïZ5c¼†¬¦{ù¥[£ÌÈj0gôä4¼` b`&F‹G¤ÜÚÓ·öÃÕ0ƒ²– pg¦w<P¸´I&fuiÍ2 DC VˆŠ¦HL»³´ÿJdêÊ]¥¬\Ý~ÕkœÓõÿ.<éöWC –•}ZUpA¦}[‡‹Eé®RV.a¢éŠ,'NÓ¿ä{P«¸ °¢ööV¬^Î7Àj°B‘búP"ÂÉÊ8@š³lr NM sƒgå‚]™ap: ìù #]—±.¦#f·÷Sž·ë¯³FwXõ{ã:x 5X€‘ƒñäD1IZ«¢shù¨hù‹!DÒŒQæ¢.BÖ¡}¼tËr AU«‹Ù*ksU—çy¶T¹«ªÍ|ctGgN}v0[[­*Ch]Ÿ¤Nöy"j°B Ä"!i´æ,ÇpšˆD¹Hº±ºqYmݸCó1šžy9Ji6âY›]I £³¸kaeFs4;&Ë]N$p=dz¿Y› œúÌM"¯¦×^K?C³žh˃Y쩺è-*Ûï5\à VR6&™ïÛb˜Íeâ|“c\w –EÖœà˜xæå)M{Öf@g„ÑY"Sög‰‚DV•»U;Í DGß„ɇ‘B “àAHsL}†‘"Z/WÙ:Á¯KŒ-4[¡rI¹µÇ­žÃ VjŸɾ sSa"}[¬º sŸö^QÛí"ÇR`‰<ع¼d1YÎÆãQ‚ôJ\WØldx‘ÍáÂó,¸¥± ФãÙEˆv’á)§>â!WxÇ0šsNs†9¸6Ìg4ßPc.šÝ…=(5rŒ3`FL()ßëfÏá‹Å“46S¾-i¬r蘌SŽò^ÍÑnž/ieAHž¢H€Å(à@¤”Lîw™_â ;´|Ú3*,…wZxo4XH°¥Ïz³v·Wªí…,¿nòLj¿¢X›õ9Ñi¾õD”ca܇“l«sÇÁ¨1Ü`Yz uµÑJÕ=Ç•øe®ZÔX“+ü³" )33†fÆKª…4v«J\ª>Ùù™£9Qî2éˆV(¹j'×߬°®ü1Qžz#VmÖç?j¹œ0ÙH*ØÓÆ}(=Düôž‹vO?Õa ( Ÿo´’å˜2pAÏqÕÅ-¶ìt…‹ ‘.)3óÎ/#VLà<%¸ªÄÕ`%s8C‰ŠºG‹|'âŠ8%wê,æÚ1‰,];8Ç‹üòz‚h¢™â›GÐ…´ø²+Àb1â ö9ÍG\l¬=‹{ú¡=XÚXí¼ò \ž¯¦›¿]0>OÓ ÚçÅc]¢q›±ñ,¥y,‹W]âò° Εög"VŒCÈË]o'éxvÕf€Å£ÑÌ!^¤æÉ4G#› ‚c€T/E4_.ù–ŒtÄR³Ì>|H€åâT”E³¬Nl3­ë^eÆŸVY Ãñ¢ðݤڸª­¦ˆ¹˜¡ê*?—´?ûvÔš¼€ÙîÈä=–"Œåirs¤9V`yfý1ìñ-'.Ó`iöíÒ"§M8üÅÆû{˲@P VëºwX‹=rýÒNŒ¶¼cVÌÌgНJ‰ ôcq¤)Ç9QÕ©ÛßÏ+­ÈuÅ Ë5?0«˜õU.)zäªsÊ7¡/Š¯â…©x,”‹ẕd"WUñVe ¡]׌ :X´jxï­ ׯEï±8;ìϵQ³“ R| >ªŒ4ž^÷‘*¾eFé?ïI.OFñL\tñî:b‰úÿD2¡.™ÿÆ,ï‘-=ŒÅ3à`YöM´ñ€ÑÚ½,ÍóÚ^ïÙì+ŽfUšV6÷—«²±¥ àöÒ&|?Ý—¤ ÏŠYú¯üÞ#âu>Í;ìú™ºþPÕH=¢VX¿aªßª¥Çâ–——èšÿV5üè'XÍŒnhföó2ÝzR½ÚªÜc«ñ1ک΄_CªzdJƒÕz¸ŠJÇ%¤ËG«¬ä1RÕhÙN%czDØ£†ûÑ X5 \MNôC«§£ût«”;?T °oÊUš C:ÖÅ K?FÞc­.h°ÊN@9LÏï¼Y5ÜjÀ‚²a@7p5K!,«¯`õ0`4 I?ê³ êg£ïŽ'†5¹WÀžB•–ž@ö§C²®Uté• U.u°h¤‚â’ L7p5Kæ~È`u=`´—ÄÖǃþ }˜ëTïæ·z+}y`!FžÃôˆWF Ëi5+š­°¿Ç®jàB¬`uùÖEi¥“ØwŠZÞ¯”˜kJ¿˜fƒ½JÅ“w6?“‹A/8XÞ¬CD³•|%<#ö¢nàjö,kVg׈´ÅJ%±Ô7²@߈Õ²ê`®úò´k]=K‚•H&K†m9LMø,9$fÅp?L¬8Ä1Ëæ+ \˜°vV*ަT›’~mdÉDÁÑl×èÎÔÌ íÌ Bʼ“@ˆéazæ(FÞˆ=‰tÜöV‰JW¸Ù`u¬Î®‘'ªH8Um™Äò«Ò™«gÄB¬tgêfõý,¤Eý¿W‰/ 9¢¼!ÌÅ„`Ùž¥^‰â¹L7p™kW`I t±ˆÑÏC”‘©¯è¬à‡™l3ÿl}gV Cuý¿j9Ò³!æUü«¶Rµ@dÀÚXü“e1WY)ìÚÈâÆÔÝ`]¶‡{ά`N]±ŠèúÿJS5 °ÒÀeê±vVêJ,3L'I>%=©1òñ,‘iÄêXmaÆH;³ – êÿëêúÁΗCYó>8`1éMqe+-|Êš%=ÑÒˆ|òÞÌÈwfó ú"eC€×,ÿ…?~¿Ýp¶ XÒ§%3‘ÑJÃ0OB\†| |øÒ`Fû¥3«ÏcòÖÔwú& X]£ÓTÑ•ÞÐú¡&ƒ¯Çj ³Ì­E2ݧ:4Á´Õ¡êaDÉ€ÕáEVÙWÒ„g”jcÜÚÃ,×÷ãz,EqNÉAÚWØ©ÃÔ€ÕéUVg®*Béšo¯Z<øÓfÏšèÉEoIœ‹.dÞ»T..nn^Ú¼´´T.—Þ;ôñ„Ã:ü#2`usí? 3¨µo·¯-Ìzƒ`? ¶¦T^\Ú|påÊ•O®Ý¸ÎuóŸ¿»¼´4ÿÞB˜uÀ–«‡ëÝ¥ ›Syc24…9àq,–˜[Z¼ôá½k]?¹C7n^ûäAyq~:‚ÚÝVOWüijz20[ÎLyéÁk70UE×Õ[—ŸÍ“Ö%°kOßz7w©ÿ0»3Kåû7O¶×ïÏ-–ò-ë„ X{úÖ[Ý•úÇ÷ý„Êå[7:ÀJêÚ‡K˹õÃVdž&ç#5Äw`¯ßd˜ÀõÛ:üK>Tyú  |œ½òQ§X ݼ\ 38 M:Å)„¦Ò ÁÚÉPûP7°`YÐ~å³Wß\Ýà?_|zxÂ}©&«ÓTú“n°âºþàýHS²† ¬dXNìY:›ã਩S¢Åqõh8ž¥±Ã•%ææé<ßt&MóU58s_Š)`öæÚÚú‡¶.l=:óöúÚFéu{WÝ$:‘³t«K®8Y·—‡ßÝ•fÆy!—€‰yNšÆgP¾¨ãS1 ÃÉÊ Köt ÒÊÓ@À²¤ŽQ¹œÃP7Ñ D^][?óhkû¢'N×»k§ßßYóÎ&/uœ^Ut5ý6)/Ì®À$UáHM“¬Rð‘™¹tÕ*9Žäÿ0°,€Â‡?suíôêêÆÚêêçŸEpÀ‘Ä~õîù‡.ÖkëÌÆÆv?Ñbå׺犇¬¹ Ï;KBŠ8jZ Ö,ÏGêÁbT®Ü=XÀ9üêê›wÞ=»õèÂööÖÖ£îüjõôçS¶÷¬ÄÝ üáôú;±’qëáÆÝ zÙ¥réNªvèþbB4ò48à0•æÅÁD–fàÔ¬(çä4þ4J=ÈÂø)ZY"‹ÂB)°€óÖÚú»g·ë>îw>åt2¢LboݽÓ+µÞ^;Õ· e‘Å+=E¬Å|®qwòa+ÑRNdäÅœÊÌ‹:y‡%¹ÝJ2V •%|“Y™¼ï,ËykcýLÃý‰V±„|±þÎöÅæÚ>³ö©Ý'ƒ|ƒ°¸y½{°®.Â{ýX«s°Ð©óï4%Îl¬Æ»¶Ø_œßj…Õ…­­‡¯:,¸’·úFÃòb/ß o—F­bÀjycmB O€Öþa|—±„4çj{냇¿Z_ßX_[¿»zêG5ë”ÙË]“uóÜû×Ê…Hã$Ë€ÕîêÀëo· %Rg×7òx7dá¦\mY_»[©ÖÚèKµëÊ'åÝ$ð׿߼üÑõra?¢¦(ì,øÆÚ»Ûí¸©õÝ}¤÷®…àÓõ†\mŸ½sw£¦Zk»/ÕZ¬“÷Þ_ºÕi£Îõ«ç–î_?ÉÁw\8²ëċǿø\?À‚Ÿn¼Ó+•ZŸj2[úÃÚMp}2ÕZ¬“7î/–ï_ë«ߟ‹½Oð5Ú`ýéÏŽqýõO‚‹suöâÅoþýËÈzØ;Yîê™Qqûõ'U­¥Àž…òâå×®µñcÝߌÝ~MVÔK°ð¨‚uâùcR/w³X å…½!¸ºø»cÿö¯_uBÖaÒYÖçðsáΓ«ÖòÀ:yò£ïÏ ékM¤÷®<(/nÞ÷Ðm°^T\{æ]‚µßVóM~-ðúš,¿þ§cǾý®mØÚ>s:ÑYŽÄ·žœóUkòÙUÀl]ýðöÒâÒæ¹Ë·®|rMéÞ•+^~¿¼´¸yùÖµJ«â¨‚uâÄ ¿xñ§/k°Ž¡ýíŸÿñ_üåOþ¦…þþÿï+©o¾‡çaëkþâ릀mßy3Bº/Ÿ¬Sç·pu¾ÝwÑ6>u"«, ×µï¯Ü¿¼Y.oj•Ë—8gWë\Ë#–$êøËÏÿüŽÓy`=ó|7ú—ÿ¸Íÿý?µô ÿöñãoóø·¿þ櫆t]8ÿ–¸Í]ÞN´ú°®.^<«*Løôv€¥¹©Q£ F,AÔŸégÏ<ãÑôÒ ¿(|áD7úçýÉßýÕ‰Ï5Ó‰ÿøÏÿúRé÷^Äúò˯ÿÍï¾ûî7ß>þu£¢ñÑÆë6ë¶Òá• ]hÕ¨‡ßº°}–Ǭ@F#iVûZ‡ëÄñ*¢”~þ|î%5ûÓ®R,H9ÿ?{çþÇ•Ýñé¾ýf¦{f ‹a¤á!èe6?XÏV…Tù‡? $)[#Ù&o@l”MÊ®J¹dKqÊe—# /JV›Hâ±Äx­5cgwýD›]­!ëe©’ȉ¤$¶œ? ÷ÑÝÓ=Ïîy€ :ÔÊÍôNßžéçžû½çžË¤8Ë0EšÐc]»~ãÖû·Ñ:e½3¤æûÔ‰”\étøéù©H&+׸ÚÁíÁ8Ã{¨ÒÖ²+l¬f§cÔýwâ8© Õ’Ž ¯\½ÑŠŽf'.Z­/GÆ_ûôù¤²Ö{ :üÄùó#Û&g´V=X¡öÝF°:°ÄÐÚÖÑÝe + –À&Û‡˜=¦Œ^¿ž<^‡hݸ–責©YTÑùxï4;q*éx0Q‡WÒK‹rÍ®Xõ`!‘½_×î°*·ëÁH4¦©$Á:9ZDÒì››÷¿ÊÑeQÇ¢ñ M%oº€:üC°{êêQ¹ê ç–ƒ—Sü¡S”`n*çê—7ãÈš ˜rYêwNŸ˜ŒsO3Éd­Bèð±Çþ,ÈÕ`.pÏÁÒ*ïtù„ ‡íÊ—÷á×åˆ?³ËèîS*ÔPôøTÜ%O%‘µò¯ÃÇná!XȺ`OØ¢Zݹp•~®0ñq§ôY·¾4D`sÓ[íœr]K0ÔÄ£zZÚÛZñZT0çg'e­¬tø”­°:÷(·€^eV9Xá]0ÀêïjÏF^°;zæ=“výÎm£ÃYp qÚQïaÀÖ·7áp/ÒÞ:;Bð¹ò£—×;I”,ëði[‡‡ú[€o¡W·Çjíî„ßžV€'qú-Ê VÀ¢œ&{Bd7î\Öå1}×X¼ïé£ûz:ã¡áHg í£Æ–æ&d­,tøt­«‡Ú-P«Ãc‰1n W{: N­(¡Ób–Œ5°ŽOšæê½«F—5;v íW7€¬uú$|Ъ? ‡áSíü˧Xìqºûl$aÔI‡×Ⱥ -L¦¨Ô­“ÃVí`œ¹<(å9ŠN+Ôƒ«vLSÆX{Úrä*-XæC,dw Q ²< UøH‹Ú!ÓÛÓ²ãù?xŽñ]áåY+o°s0‚WÉJÓ:9 k·€"½Õà±JJ›Ôuz1°Âðïëi¦PK®{&°À袩GIìöƒLzé`÷I©êñ„÷=Å ‚ÀCå­46u4AÖJ­ÃÇÛ©¨¨æíPTŠÖUkUnÁ»J<EWo|T’U°Hp¥%C°Úsæ*-XlÔì³DvõÎuý¯óãN´ŠSy´.wËñh›RÄMNMÇ]=•ŸÄf§jKÞÓ´N6G·Àq¤–÷J‹ÚVóê¼Êð†€ ®Tk:ÇÀ=X”/b®ó!våæ×ú_ÇD«dj»9ë¶r • œI…k°Õ [ÍMÇwÂSf¦›‰n‹…Y±mÒõ­«‡ä”úô+¬uk|µ^ÀÔlRéa°tÁ•jáÍ/سX+´RÁ*B• ¥&–õX®¾eyÜùÓ]ýÏÁà*”±ø¨¤½š*G^R+˜J’´Ñƒß?°¾¹c˜.\m¶8©÷I3q²Ö9Kw‚øæä ýV)Xe5^ÐTÏ~®¡BàÐÞè€îƒÁÕs(¸ÊX|´þdpOêEà<ø éÁ²cÝ»eÞǬ€EÑ.}c³Æ®0™ŸÖf'¶f ðV XtmU/‚²Æ*N¬ª‹XVZ;vÃàêÿP/˜±øh5h•ð¹õ,üÍ)¹€àfT°”‹šFè éÀòŽš[ÿŒíÚ͆ßçÄ">a:õÇ÷ŽœÒ‘dìú’èðl¾Ø!¨}¡éçºBÁÚ^I×—lhò¹Öp,ϲhÓáÖ}(¸zv'æ&cñQdë·ƒ­›µ³[·ƒ’%è,å"ð þÊŒ1V²…3©–±'|ïÒA¢atÜ×ÝGeúri°M?1itQ‰:|&[Œºð£¦l¦Z_±`ñÍ-»ý[$‘ã6Usxt„úƒÁ=ÏìäN¦â£ØŸU‚»vV¨ub¨ÔEfä"ðdÅ£ÁJ²À!¥]sXsÇ]¨7¢ÚÚ[zÂÆšCIX(ZÐûGã(0Q‡ÏdpLjl=E³†Ã•å+åSUÁoxÂS[á"½ JŽiiª—WÁŠb«+cgA¥«T*¾‰ì¯\Ą̈ÐF_œ4;È¿r÷¦ÑaÍŽ–¹|,Ø‹f Z:ºB!¼(¶RSYt‡Dªu“§ (%èðm6z±ˆ—÷v(­kù;iî`‚Uæ£×¬¬«n«°¶fFí(«}O0Ø3ÈcÃd,>Šm‹´ hgÁV÷zü?duž@…zS`Q´ÃtÚÌ×w¾1¾pfÌ¿ì®NãÚþª-á°ƒ"ó,Üø¼Æñåóºè=Q‡ÏhsÓ'“jë; -ÓØVœ@ZV¼¡†æKœXí¶CŠÐh°u_O0¸ûÙð7Ô/b2ÅÆ•ò@; I/H<>ã)uûÕ‹˜ôX¬Ùèý£8ŠœÌAÑ!È€øŒç_ØÙ‹Å&Ë` ó)Ðe¹"ZL7Õ…w :¼ ›w \Hi‡©©gbw°²<µ¥šwU40ëë\%ÅNÌ‘ÌàÌãïïäe¨J{Á,-XÀ\uåë®f'Ö£A!JaÜÑòøwwïÉXHDÓòÖØ¬÷”.ÈJÐáMØâ¨èãeµÞó´"7EÞŒþVÇ¢(º2€XÁqÕ¥5‹ƒ!”yŒƒ+ŒmfKŬ¯×I›èGo35_»qózükç"0ÄâðÓôò¿}Ëh[£&f°(á;à/hS‚gt²ÖŒåؽßo‡`1,n]6î[êV†Ç¢°ÎîÝàgdo}Ç Í¬‚îÞ­WëUö¶6 V¸cwϮؚð>éZéÁâGO%yhWnëÔµ{·¾H,›5?î xÇ š‘9.ƥˑ²érjlx[qá‚ê³æ¦c-ÏD­ª ˆlêaë½Z‘«nð›æVXx…hÖÙË7@?U]j‡`yá_X ®p/HÒ9(³`íëÔ¯Cñ…‰…é–Ar<ÑY\¹}?¨‚uåú[ÉŠ7ÌDkÉzE’òDS´-wÔ¬-‡Eiv†ˆ,Ò.ƳÙt…cͤ+VÒb(C³Éïà[–P-¹›išèìü†jGYͺu¿¨]Ðê°ðLä˜Ógõ°Ä'ÜRM9ÞvC’`t-¥êÆ…xä¨Í5Œ½XzÄαÂÚú& W;`/øÝ¸àÊXû4°ÂVb¬t…×Ff…qý²+Tk 6q#ÝC™8éqfå°T²çñ‘Èô©ùˆ">txS¶8êqZÎÈZ~°èb ›» ¨àã‘RˆÕ ÄQŒ»¸´ª¶^ª¶£õ!,ä „¿–uý!š½ÑWÖÀjÕÊ„ìf(¼Æ°bÔ8cÙúâfšºÜ³Ó#~¬ºgY« FÛ,/8NŽEÎ+dtxS6¹Ðœb{›¬b©¢ŒgíÛ% ¥ H(ÃE©'gœÀ§(D-Š®•Ç‹õ’ŸÅÞ*Œ&j{žÁÝQ®âP4)7 ’~--»Ñšñ–þnè¶ÚM•®ðd‹õŸ_yuåjê¾pn~´L ÖÓìôd1-»³yÛ犬5e1Èš­ûÌeK”Ü‹”¦õR½W–$èwdÒ‘uq’6%FŽÛ\†•pD`ÚžÆÁ•àó'ö‚–À­¡®®ánUº0óžt…×ðpŽf¸òÈ¢éç:7ÝÒŒ:Bý ›RÐòÙ‰¬uÆR.+ê ýXî°ØîrƒÕ$•£…–,˯÷°^Iâyèµ`wRR!U<0Nöz©t p‡WÑ—¦ÅR;ñUŒ²¬ë»Oq¼ 4{“—Ñ´¼ISk¨^5¸§_æ +]á5õ!sÇM“…¸‚#Â,Î †\%Œïx¡ˆÈZzÞÌ]L^øAÀú=,7Xt…d‡“!c°Ibeo%ƨmê-¹Ñá¿Âà ž7ye/ãe]ýƒNŽSl~›Õî_!”ÓììÎä¶2oy}\Q-3ÙÌ$âÊ‘E™÷„ÏŒ—’z9‘µ-Ô½AõÀ·Åò¢¿E`AŒp4„Œð,Ô/Ö88G½´…e ^¾Jr#WæóÅÍ4-øð›Éšùg{qrŒ—uÒ©ò¢²Ênw÷ ·ÕJ;1mb“&DÖ¶¨™R/碣*Wy¨º®ôˆXÖšµ”935îqZï °88zS+©°¾R²ÃþÌ!Õðœ$¹ÁGNØí ¬’«ÑÖƒ+2-ƒ-GŠÈz¿ÂÖ®]Ð!¶<Ý–-`Á,s?™8—¡;œ[<ÿyY3â*ëåâ¿iøMÉDÖš2Yk†ð]›Õ°tÙÁª“8ÇÂ#r,AR¬ÿêCÿú \vß&úS¤÷ªÁQ®à•ŠR>Øìó±p_Lƒ–©ý Qï8=•¶;š¹=Ù :íùãÊFFˆDÖš˜7;€À:š/‹ai¶`}\—Ÿý é5R9‡è>©ƒå# )æÃH ¼VÂßEãe]8¸Š%Ç8 –l¥\žo ,<6ŽL¤Fkf*:^æöüôƒú¦‰¬µpÞ¤–57?Ö¥ŽŠßͬWܵ|ì M‹R…ÏæKÛ£‚U'9Èìvô«€â+|BHØd¢É²®^¤:¨Ê]°­{±×jIk™Ýš†ÑŽãâÈÄÔådÅŒÏÍGÇ/zD§ÃÇçqcJµiiùì'"¦ê‚Ì-FÊŬü¢RafkÕøžðýêæ¼l6NÓõR£ŸgŠŠ¥bFöª`•H5‡«Dª·ãèŠãÈ gXÔ^²¬‹3L rOèPwO0¾V5°l8Ú?NŸº<«ƒknöÜÔDt|‹Gt9 »ÊËnIñŸ£e¿`¦â äª Í€g%üÓÞ'>øØ2XŸºk])Æ ÖÀ¢hž( R5'³,‰¯|ÈeáK$±<‡O¸%©‚c ²,ëâ⦠»Ù8V÷ Õµ,‚…G¨Oòo]™˜¾4¿xôò™ÅÅùK£# UeÈ[ÁQŠœßÝ¿cm#¬}3“E¸Êr¶ã{ç·VÉútãöæTÞRx××”–V‹,JR':– ð¾µ’»rÅ#ÍÔ‹O”5JnXxÍ¥½ÈátŠÈ\.—Óé(‚TኅK–DXÇÒKS &1W¾ì6¥¶áÖß½o…¬>=û+…äd׳œÝ€¾`c…ŽÌÊ2t?ŒŒ'±(¥œð¬6ü6W‰É1…‹T›Œ µ¬€E4K€>¦ øìv{üã_!!…¬FëÓK“º«ÓcHŸõÅÅ º 6ðNÝo~ý‘)¬>|å³J¥E:/`Ù”Ò•Œ~• 5rt'”R¢JpÅ3µÏTp°­ßjYKÉoDó ^”óÃcÏ‹§§Ìæ•ç`¨£PÓK“`uf2r¡áQ_eí¯lŠb·ù¬û³Ÿ˜‰ªñÛ³?[‹áÔ$[OôS“ôiš2”w´šBé—¯Ù(ÛYÖ…±ò2‰Ó‚K–jõÄÖˆY˦"&oVòé% Š´K/MðV“çG6y>› WDWœ¿ú鯯þõ“R9®?üõoÎ6¾ûWþfn1•‡Ì:5YБìd%[†Ò­'ÂK]ð¿mhY™d’'Ç, X$ÔÚ£åÔXËf‹U´Vÿ„²ÖÚÕ¥—ž›™UõŽ™ÓSc‘ñr¿Ÿ«>‹;_QóÛõgßÿà_~þ‹_~ÛjüãO~ùʧ|v¶±ñýGàPbåÃc–+ì*øöê×̃É1Kh݇ƇûrKùXú5KdºôÒÈÄä©ÓgŽNMF#Ñ‘eDGãr×ÑTAÖÙ\ûö柾s¶qãٟŬqcÝÙw×lß„©‚ ¢m5R·X`°úÈšyŽO\©ÿ¯%KIÛÊ ¬å±Xzé±ã'FFÇFÇO/ó7+O9/‚VÍpž¡#Ǿž††ŸhÖÐÐàAòŠËpؑ’~(\P°”àª7Up¥ØR‚EVMïF¢VXyYÎ`QÒË/Úl?<4íB¶^–0MÊì¡™`xyÀÒ?G½xµmÅfTرÞ#~Fy•X®`Ñ’ÇvàÐð‘á#CGÞ>üæÐ~›GÂYoèÙ™®,Xþ?ùƒ`ðéºÍ"—‘…µÅåÉʇåýêÛ¡¡#CG‡Ž:<üæáá7lû_U ošÜoc¹À¿÷û-pŒԺŒÃ]\ÖTÏ<$+wË ,êÕ¿ßÿcØBwÿ9rdú¬7_;pàUeÌÁË–Gt¼ðücÁ–gÂÊXZ®(Ýwñƒ/9| ,'°(iÿ…*øŸ£ÃG‡¿þÖëöKV–B-X.»À?Ù ¶÷ÛP‡Áª5à!Y9[N`Áø ù+ÍeÁƒ×þvèGo½fû;‰7ŸÔ¿\`5;}<ËîünK°'„É*o²ÌÖ•3ÉÊÙr‹~ÆW‡þñÀ~f9òÚ!Û~ÛÛá7_Ãö²…r>Ë–Pâ>û ´P×-¸y™mjäå’õK”À·r-°PGÃ*8´øñÑ¡¡£G†áñ‹0Ìzý­ý/JæN.XhÑ0ªÜ7øXpÏ ÉÖV¬k¬³{K¤ õòC²r²À¢_²½quðøÀÐ?@¬Ž‚/ýèuÀÛ$óõ —,¼!ò áÑ>b¾òÿgï\˜›¸²¬îûj=o_IÝ’%¡‡m=eÙ@Ø©ñÖ¶S«©¤j7¡6à-Lx$Æ[Eµ„Lv'Ù51C’ ËÄq²5¿uï¹-É6X¶,ÉtúhÈXRKV»?sî¹ç‘eÖ'c¤z: k,¬Vè'åYÁ‡Ïÿ ‚Y¡ç[’«'¡ÖðÝt< «™2’¬ÇY¾åîæO™BH#øYãÈè`é|óþøV߆6ÿ ýõùOrU(Áz²ýäÉÖÆ›<†Ìí÷,7îò:eI´"vLrµX?ŽŒÖ×?lÿ *KBõ0ºÿ|{ûg Ö³-écm}âбp¸y^‚¥u33o-9ÎÒ*´FePˆ{2&b倬Ñe°BRI=þùùvhóùß$Y?<¦4–´…O¤“¶½×`¹éä·®;ÎúeÕ­£S'Œ¦É²F–ñÀ’ë§çÏ$XÛàhý°ýL‚¾ûÆßJ°ÂC:YÞƒå*@ØaUåÝR3Ÿ«7ëâÛì•‘ÁÒ¬gÛ?=þiü«gåcO»kckc;Ä6\ÀÁ`…Të ë2€5Ç ln†©L@Öˆ2X[Re}»­4–TV¡ÿ{þ3€%Éú±:J3oÀŠï&Z÷AØa]‘ÅË%N™yÃrF“±Àzúl[ê,0…?oo?{ A‡Ðã'?nlý¸ñ|"`…ú©©Ç!±=¶Ú ;¬uÉÂå\.¥Þˆd"c…þº%¹’K.¥-ܲB·6¤ÆÚ¸¿éšÂaÞé °1¢1UD7i‰Ç^hR¶—¬B5ÌÒiFã' ŸWîøSÆÐX¨ÚÚÚzöüièáæææCyƒÇ7Ÿ>òäÉ[•¡§æ–Žô¤:‰„mà»ÖZ|‘Œ}2iЉ ?kCc¡¡§÷ªŸ[RMÉÿ´ÒOïÿå‡ïž†xzè‘.€¥U¸Ó+&.ôåæÙŠ,ÐY0{ ÛV.ζ«ÇÐ\ô—/ã€ÅAEmþé~(tƒïÜøÆão¿¾ÏÏN @êÚ'•=?qAûe·ï!«:EY…碪±½×êu“ÑÁÒtüGIÔƒ‡`7Q}i…þXIL`K'ÔíIuL²Ïi+²:.Yl&uºÖˆ0:gdUÆÙ„F<zÂùþèÁ¬ø“Pš§cÃÆG+ÔkÂ5Y *ô^EJ¡f…7KŒeì`CúÈ2XºÅ7~ÿò2^*1îN7Ë é’µ;ÒF“ÑRs¾ÜXÈ:¢Œ“è§#úhóá“ÑÚøß‡*G™à/°\²g™ Œ-¯22»lîQÆJMÖûófèñ£=\µB’+˜4:ô\bŸÕ%«sý–$kÖ>E1¦N…ƒü‘d¬b YŒÿ)´Ùúžo<øþÁ£Gß?ú VW“(¦ðH +ã’$ tV Q±«…\ # kh¯ü ãPbÿp³õÍ7ß|ûÝý‡Pb/í`ä(Ö|ukÝéÜ€Þ µ*–ˆWc¹B`‡–ñ VUÃÕ0ßhÝWw¿†¦ •tâí_nãÓ×ÒÇ ¹;ÒçWœµKPÑòeAHô¤]rJ‡—qKìÁ–¢±žƒUIŸMÄ¢¿^Yº~þ ¶{“ÿÀRIÊd±E“ó± =ë2vSÕ¼¿í¶[…™E×§³rîæù÷†j æG°@g}Ai g‹‰ôL’ÕÂëöºÈømŒ ‰ªV¾ÑˆêÓL…ø¦æ —ÁRûï8ÎuiÓÑl“·,5ß$X+“h¼Ökå˺ã¤\pz²×ïàC°€¬+ËPn(Oh:®Z»‡áeB­"U+ßn«ú•ug—(¸îîü´·Ë¡?Á+e©ëÀ»»Ö¯jrÎ/A&Õܶ¿W¬&ëèHú'{eí|ߎ \í6Ž> ÈZ]qÖÝú À g¦²†”ÉõyïöãV"¯Áò^®:Ë;}ªÅæÌî´L¿‚dÉ/Èò­n/õDŽWg²†“c  ¾ë}yçŸ>ÿ‡/ûÓVëvO›s;Kwß‚¥¹_ª‹ÎØÓÆ”IJ†“ãKG7zXýó¿}¡øîtuͰ‘°âöY¾K9ðëÎÇPÆÎÕ „h"è5œ×È]'K=²þãƒÄl¸×âyÒ „¤fúáFÿ‚_ó+*še-B!ë©F.dý #Ç–ü®_VÁ¬Î;Žó?_¹ãôà×,äXÛLSZMZ½Ah>«ëfAÌA.|iƒ/D2ù@e !Ç6¤I:%וõÛ•t}îyÕB äÍk5ž ½"?ƒ%½EtÇ鸛†©w£óŒ™¯Íð /åø¦éˆ\°>øà_~£¹ÀåÐse„I¶X/Ç ֭«ò5X®›µ¾ ½ÿš ‘*0ÓyTü$Ç–¼"—:RYIÏý¿ÿÑévùÔ)Dé³632|Þ¬»_}_ƒÕ=;0!ÕF.™$"ð²•c„©ëâŽTY_Å"¥¿[†Ù…WT4!œåt'XxþmµI¢ë¯ÿ ŸZv:¥1dr:Û,+°…‡ÊqŽîUÁ¬ÎWîÀnü¦‹`wü]=æíù·X9o¹;@Q¯ÿ Ÿ‡~kŹaR#S…ñ“X‡Ë±‚%WTNçW%ZH.]ƒ9¾jÈŽ¾ØÈY%w¦Z`åBIækÆð†ÓùƒJ'$‘i–IÐÎá09ÖaãÒž[6 uE¬[w:ª,¨¬t¥ÁŒp’ÇNÔÊf¡¡5–6˜>mç¦kÚ(CþÔ¦úÕËêî3v¦ÞN*ë09V°`EµJU–2B‚~>ü%µ£KŠ#>Ëš)± 1;Ü0’<÷…ôÊøÐxpió&oÀæ1d¸Úmk”“ÕÑGkª M5±j¥€¬CäXÁ²;´Põb¼¼äÀH$HC1ÚœŸ‰éÃÛ1ê\BgµE]çî×!^Â5½]‡nWex•$ºReY~úën0k& ó=›ñ çï9^°TOåhÀ˜¸uBZç¡KžWrš•Íp‰ñ¡®ö”|H!®£.Zý›â¬÷s?%G“GrÈ£¦|•ʪ²Ñ(HèúùeFp ÀšãAô09f°Ô\l÷ÝUÓköV>#ªU?9‘¢¬–b¬š*7³ÁzM+&OK.É“Bל£òÍå=,õÒbŽ'ú¿S‚U,CmyãHþ ì‘6‘å×â‚TYTTŠ•JÕ<ÃÈH|¾ArÜ`íð´Ô°­Î[êb¹B¢Q`§ùÉ\ýðu–ÆõXgHZ*¢ÌœžÎH”²z"'])¦Ïå‘ÎË(Í{™žÒüáX#—OG%ÉAë#ÎŒ“þûгÄiq»lš®*ë@y•`AkbéÃßøØq®A› „i¾˜1¢ö™4+&½P.XðbqM°4qÉd‚JLåO4‡·æÝÄ M-%b­¤•`I1ódÄ´r¸˜nÚ©-•sf9¨Ø9P^)X]sxùšã¬ÝPÛºXi 49“9tÊ·V4@]U¤Û„,‹+5„iÓ¶g-¡ê…½$¨AÓe0–ˆšòA…À£æS)•u­½Pb¬À“”ì,¯,×vCZ«ªHA¤xÉHÓvJ„cÜÒR‹òñ„<‚˜Tþ“¬H—#– Ë5Bäã–¼ê¦$ÈF–H×Ê"Ü¢ª„kD ttSª,ƒ±0SJ2›øM”W –Û›˜¸!-èÇç9f¤W©²Öœe&W†In¦ÂAòûâX»CZ¿þ’2VJÓV ʨÛyÑžxñµY:r³$v8sùr{!»ÏëÝ2Ú.‡½ÒÀqÎTG眿”ÞU¦Båº4hxx–‡ï†´V éc‘¹Êh”'²¼ØÓÚ§ƒr_5¹wÐNCd-Ôz牱NT×Ïwœ‹LEwÅL9Ø0<@¼kOHëwÌHR,‡Ó¹|Øž&¥\}jqÉÒº·]¶5w»çÅ#´!7h´¤öu0ªØv±mÎd ¯ÀÚÒú×g62¶] 3mFi*9¸ýƾÄìK×~äAÞŒ»¯8bŸè{ÎÚߨM'i¥IJŠg`õvxTHëe^,’š75rÓåBxðOŸ+Ô½õèÞÙe'÷<}Øð€CE[xƒ œ¨af2ÆE~$‚冴èÅÇyç’\Õ ÁL=¶k'f æàžý57š¯£uçš´…áLš‰Ê|0 e x ÖžlKc"µVÝ.5S,jȬs4þtL~„Þ»»DÓo:k«Re5¦33v…ˆ@c oÁR!-‹}.ÍáÒe•ð€ÃvËMÿ›ÝßÑ‚™«ËvÐÏ ¿ý|§s‘\*&g« h¬â1XÊöÛuǹ YZÍ’Ó´`†KD³ø¥“j–ïÀŠÃ÷¡ßýë¥-„u!Œվ0ÐXû‹×`+Ži¢›¥¥Â˜*ýo± o¼´yèΈžX±a§t¾ðiõsÎ:ô¡@¨¨b¤ÆÚW<KÕòÄÝ–mŠŒ\!Ý(° £ßãiugO¬=ƒÆ‡—ž“…D¾díVЕtø,i_b[ý,-Ì ýJZã´œßíÅôfÚO¬QO[ÿÈé\dN5éZ8Ç‚éñXQ•¥uÝÍÒ#Ch¶HÓ¹éja×ÜÜWž‚ue͹!¬f· ¤æE?€¥éÑn–Ö di!„E* ÊJI%ýdŸ+/ÁÒî‚÷Nq2†g²F1, ˆ?ÀЏ!-kuY…´,1)Xº$Wô=°v¸ò,ý¶³Ä¨ÈÖydº4ž$þ ÚíÊÒ‚fPÒJ{ÝÙ´]\y VH_’`1§š‹„‘ ó}ø¬]YZ«†9½ýn®<×Xƒ|BÈ. 6 ‰Àr³´¬^HKÕ´âîtº=\y«±.8+ÔèÀç ²HŠŸÀÚ¥µ®vx[ŸÿWÞ‚uÓ¹ºÊÜa4H‰¿ÀrÍ¡µ«ðÐMÙ{$¯5Ö*#ÕF­Y­ÎOÇ‚pÃþâ3°z…‡ÝV_a½˜ôâ!XçœÛ‹™‰ÊÜT¦‘™láþâ;°B»CZn‚ƒ¦OÒäÀ‚p+eÁÇ ·pP¶:@üÖž–;ÿ×`¹ýTYP` ÷?‚µ+¤uí<”žNÀ©šXwWœ;F×y º‘î/¾kOH .¡ÀÒ>í87 œ'yþ ‚Õ iÝé8å[Xø¬{NçSmUaú§¦WPöËŸ‚µ7¤E}Ö‡Îú*#ARÃaâ[°z!­%ÇY»î°î®9× &Ë*þ«ïÃwç¿®ø,ײ 8çPñ3X] Wîù¬ÛÎ5&],—‚ª-ôÈžÝ+»Ò¾Kùð˜¬.ý»Ó¹0Q¥5*XïwœÏ#ÞEEM››í0ô§°_øü$»ƒ 2÷Eè]n‚sH³û<+_ÚïÁÙð7X®9$ì?× ¤å=XúmØ(¤ÞYÂz-Štz¶×u£¨ï)ŽÓÚ•þ}-ÒT+Ö„šZhÕÊKeuêU/?Iî{äâw°ÜÂCþÞ{Ïc°´›±B^ýÁL¬ºÉÅfžnå¨ê´£Le6¥ïi2çoùëº:Rßõ„;~AÛ5“¡;ˆA¾Ïˆë_߃daŽ®|Øq:ç&fGëÓŽsí–§®»m¸Ÿ?‰P¹…P×u”·íyùÕÞ¼ž5ù»–®§N·ì~Q&>Ñ?‚C™³àÉØ»Z±’ãm¹ÈÕRp¸ûrM«Ÿä5C‡÷ÑG\û,¨â‘²÷îIs¸þ‘—`ݽí\½ÌØhm&ó—jͰnsBT=‹ù"BÍÓMŸÒ‘0å3góµª:j&§³©"KŸ© ½2-1™ «ÜD8²VdŒ7šìšQ]Oä1jµu½"œ+Ê#𳣦2¾`¹›Ðço;ÎڅɘÃQÀº{ÎéHÏzY?¡gsɈKV£$¹¸R…QA ŒU!Xž1åÿ¦„E8Q;äÙ*ŒÊÊÉ'lM䑨šÎ‚zKégsc˜4¤›8^^,!ƒ‘9꼅׬^vÃ{:ŽsîÊ$Ð,Mru¥z˜(nÁÙ…™,”øÛ‹¼ƒÈÐÆžc‚ØÝýb%W¾œw®r“—N “6’p%ŽX#µ ±eÕ›<r*bRsÐsGcAƒuÑ)­RõÎ)>ùÞsÃIy3–Xo_ÿç‰ìÌÞ1 ­¾AL“ØkÕÄ+Êá¹ÿ”6XjJëÉùÆð÷ÿù¯[:VGŸÞ ¶À5ÖG¼}ûúÁ«7#Ù—îÂ]Å*¹Êårgl1¯Éä/ÇwÑœêæÈ™E¢Î©Ë7XçŸÒúöÕ_þjbutüùÇûþñßÞÿûë¯^}ñf4R›ÝþÇóÇ2V¶¡XMyF? çEÝœ5AÛJ„¥/žŠËá¬}Ö‹'££Ç÷^Þ{ùr4}wt¬·|7zúìD† bu‘å~“9=g>yÿŽ$÷áU¨Ñ—Æ ¯ˆö.:X0¥õpÆ\=xt4αù8žÞ~öüë“Ç&T&Us¦fƒ%øõo~v[¿Ëûž,w*×*gñÕÊ/úg{ñSS9ì0Ó±]Ü;dÔQ’±¸ˆmÖûþÆ¡ø97”vL”DLr×`zjÈI·ƒ¦TŒÉz¡Ù§ÖpÜ[¶* %4냈à¨=äÆ Ñkåúœ¨¶á.Ó²¢Á*5:¿øå=ó¾Ð—EEáêÑóî«Ô¯>ö‡5Fí>íœï )•’ñ¯ªÔí¶òŒi1ÌbÍ« Ô‹jϱ-±éú€ƒx|Ê[mì2åÑA  &w-ðûX œ÷²èÔú¢-]×»L}RV5Xj±ðÙç?—ÝÖ­;®M?ëσ&~jÊö¥¶Íh¥AËŽ½æ1HÆ+â“jÉ­ ¥˜|š[Îj‰õ óêÐáxe%F)¥Î)oYŠÇ7»5[DôJ¼ ©,³¢ØèÔÅœ<"%ÚvÌ.SGeeƒU |ßîüìS‘¬»žMããŒìÀÊ´ºos¯EÝ«5{P…¡Ÿ8ëà xenŠpõѳX•?$Vµ^•~žøqò…í>ç»Ññ–¡cºÔæ¡ÝlÔd¹1ßÇÈW(  ­Þe×aUƒU-ø0`÷üŸüô“[·áÙæ¬eJ"þW½›othqÀí2|ɸ kYùb‹“y>”ˆI±\¥*en¿Õ½Šq£-y]‹ÇÚ[–mø~Ç6aܨÉ`9€z¸Gé°-.–f—é«ì¬j°næa\ÅlÇõ¶~ôc7«+—4*”÷¹+z½âòÎúpcsñI¶ˆk¼‹­‰˜äŠWé;ˆ¸×¡Œw÷»ÝoJJtÜ[®Üß²mm7׸٣ïq.uÓý€²†Ð–©=¦þW5XÅ]¯&ýn;Ž3ÇGßÿ›W)_·Š ×ì&LØîì1Þ„ Sk1Ù¶+Tõ&Ŧ§r¥[-Æ·êãìDJʌƽeÆoì1§ÎíZx¥&SV‡ßßÓ«;”íçeo§v™þpeƒ¸Üø!ºž|ïÛØå­MðŠ œ_o¯íˆLm8^·Tࡘ̔DLrùRd*ù Y­CHŸç‰MR<þX Ð )=xG™¡ÙåÛ—·-Â7‡b›Ôo2‡}tÈò=xΧ牴ÝvàûÌ`­p°d/e‘læJ>º5¼ ïñ®º"]F2¶÷KÍæ˘ÌXÓ‘k«%ÇBòí!¾QŒ¡+¢lÜ[–6²šÃƒh5™ÁF¯W›º££Tï‚Áš*Xz®9SVS‘Ç`RòŒ¼d=-Åô D²R,%¥cW”õ ¦º·è áÑõ·ˆšª]pºaú`e¢]¼quXýkTu}£ÀÌb¯® mw3=íkò§^Œ%…‡=/+l;Ó’T¬lCôã“|d:.&k F»¡ÚI6Y íÒÈ[þ ÝÝ…ˆ)¥Ó‚ÁÊ8dìCæÈP]äÐÆŠ' AZá«PjVš¨šs‘-o…MMñ¬ÙF¢¬#n!Œmw ñ{ç§n'¼ëÞḂ‹…§ÚÎ I ’ ¬Õ¤ãó—Bž ÖJ¡K+ÿ4 Ö²¯v¬ååø¿r»¥J+=Óz± Þ k)Ð…‘ITÙÒ.±¶’ud)W-‹‡ üzs7ùSÁZˆ)Œì–Ž.‚Ü t,f0‹­NO–AÑAÞ¢¢’œK­*-‚½œð„ÁZÂÂÈŦMeäxÈà,K³X—Af¬Ø…º %g§Ô`,è'_ðƒµ ˜ÂÈ¢¢\*}ƒ“~³X|Í-@d~­Ík®èµ /CƒB™q(ƒ‹ÁÂ`M8Aaaä}ŸCmÆBgyVò–.ƒlƒt\0õûdƒÆVãWfpާƒµ°02HÅP™+ݸÆkí!Èzª ²ã@ieY”hо$®•m’ý™0XK1…‘íôXÝ*ãÆ%¶¥•¬Ë »n½fƒ‘Ì›5-9ïW¡A'ùê_¬%€˜ÂÈ»Ý+ž½½ÎX¨³žÇ¢2ÈÁUÛúÈ¡äÌzÈÝÎޱ0XOv–¦2cF7–f±.ƒì8 ÃøŠE•”Å×˵sG~'¬e@ }".U(?¡ÅâÈYÊQæ $›úÊ Ÿ Ö2`TÑuŸ™:92[42‹uä(Jú3ã)'}.0XKV‰OAŽê›Äå³4* `°–c¥›¢^Æ267šÃ IƒÜf#9ë’ƒµ,h!>f¦‹Å¡ó›ôåÄÁ`-®ŒTÌÁ`-Ùù0XH*`°TÀ`!©€ÁBRƒ…¤ I ’ ,$0XH*`°TÀ`!©€ÁBRƒ…¤ I ’ ,$0XH*`°TÀ`!©€ÁBRƒ…¤ I ’ ,$0XH*¬j° knV_!X9«”8yßIºœ+g1‚Em/ÈЉQÈžÁJ“Å–Å\Ï_ cÍ÷ÄoÁJ‘…$ËvÜqlÌUº,F°d©C–”&_Íc1‚VBLŒUº,H°`/¹bcä¦*u'XÈBÁBRƒ…¤‚Ÿ…{–,Y¸·‘øÌ:2o²qo#ñ™udÞdäÞFâ3ëÈ¼ÉÆ½¤gÖ‘y“•{ÉϬ#ó&±RÙJlf™7xoAAAAAAAAAAAY0þ\)µ”xîlIEND®B`‚libfreemarker-java-2.3.19.orig/src/manual/figures/overview.png0000644000175000017500000001160411723544470023723 0ustar ebourgebourg‰PNG  IHDR ¿ø‘*tEXtCreation TimeK 7 jan. 2003 00:26:51 +0100ÛWtIMEÓ5,Éõ©í pHYs  ÒÝ~ügAMA± üaPLTEþþþûóóòòòéééãããÛÛÛÓÓÓËËËÃÃúºº³³³¨¨¨ÀÀÿÉÄÄôeeâÖÖÚ¨¨ù%%þè§§ê´´÷¸¸ÀÿÀ˜˜˜wwwˆˆˆdddWWWEEE&&&777ç™™UMMùȶ¶ÝÓÓè{{؉‰åWWç99¹¨¨ÕÉÉçHH½ˆˆçccî((ÛUU訲””ÇkkÉ™™«——ôËË≉»yy÷˜˜ø[[«yyøêê÷©©Í<<êI))óÕÕõ‡‡õ==ÎZZܹ¹™++àøDDúxx×aa¾ý¾ÙMMÊxx EE‚))¸__Øuu£ Ô::ëââãÅÅMlj‰Ù––´ ¯ff²ª@ÀIDATxÚí ŸÛÆyÆ Ì cJ^H6ÎAÀ•l9V¼u¢H‘*ו¶‡”&mÝZMÚïÿAú΋8tæùí’ÀpvIâÏwîy¸Xý’dYÖ¥_‚Ñ.Q){#Z±E+K@cjÛÔ^–MB¶]#²ZeYÔ²-)*ò¨‡hg6m¥M$QL°“ÓÃÊ2ðK~ùi@  eAËȆ0C„çâDàSŒmd4‘ ‚0Æ©‹‚p¤Øg1àÊÓE)Ü!Ä|•pTç²yÔ Ò$B“‰"¸HðK‰ú…ž‚0B<‘ÀÈ%ÊCN’pdM& X´8ÂYÈèàø‘¯™ä¨\HrxªH‚”K¿_® p"©(@.qJ‘RÄ'hðsx°H%@ÓÉâ€2D…ÀÕ/M$)ÔsRê8Ôu²¥“DBD–z™çD"éÒoã—+h?c­8æU€DÁFš;"%be €rê¸<—Œ ÕH *ÉDЄ²mèAIñCøá%/»„x1戲¬*âì:?¹L#aBY¼Ï)qPpõ?£òÊ# Ô°K@Åò‡g2€&”%ñKn7BÕ•W'䀂H®´MGh:YŸ®d€ æ¬MÏÞþ3ä3ŠzY4 €‚¨_lU°¡~mGêû†ØPÑYe:¯ƒEÑŒ¢Ä´½Êšë˜Æ÷0ÙóZºÄŒ/ ÒÌ€|Ϧ¹-¡Œ»ô{¾*mêá5"B@ei® ZÑè0¡ã12€«ˆRqCÅ EòWÑ¢ã 2€«DëØQCÛ'#!2€k+‚ú™º”zê @¦º˜zZq*bF§c¢™;ªÐP@šËÒ\æ2€4—¤¹6Þ°6€Î”¤¹L§¹ Íei.HsíD·Z ¡¼ ÷0Øû 4XÛ­¸¦·Ð>Õã;°ÿ‘5¥iV_â­xÈ¿;¤A€ÂÇÇÙ€®zi)Ê\ùYó.ÊÅæûÙN9C;©ÙÕîdjØŠ ©›5g‡½{wÍ„bOlâHª•ÙJóždÊXÏ· HîA¨ú«ýÖ°¨s*zá€>Ýß¿³¯wãÃb›M!=o¨%WÙ$ÜÎ,•2¡þ¢òi·ªX©©„m@aX7"ö ?¼»ÞBTî!„;ªî0–,™HAx¼íŸ;5uPP7rÂͪ‹8´~ „>]íF¡ Pµpƒ{|éÀR§à-vÖA´§RÏŽRõÒÁ:¡ûO#–³Š‰=º˜!aˆ#Ýo*§‚&e¼mPÃ:ªG7³÷EBŸ8!|„bòb¹å½T;° ÛQEWM§+Ûv3€"sgîì¡Xê”ñJð õðíÈ×KÈr £ºvÂ-À‘S(Þ¤KT§LÖH˜¯cñõjífW–*ÂÆHšze²rÝ€¸ Ãõ²j‡ˆÆù¦v`©s®ÐâÚ µ}$ø-E•‹b7Ú»².4å}ý„¬¶‹p`éz¬Œõd—Z“pµ„j0·œM@ÝѹM¬ÖtÄ”7ô¨€÷ãì3Ìiy Яür3ª§âDøqÝ•”Ë­éFúÔêgŒsÁ)ïá„€ YIšæEQ°’õ]ž¦Qäñüy[ôËu”1Î%×$lÚsi-Ûñ“ŒóÈÒ4ñáaÃÜ NÓŒ£J“¥s†S5/ cŒq¶Ѿ6ÂH7¦¼7½}ÿqÇÇßÂË8/YžD¾ƒv½äøQ\0ȵ$'6¤ìycŒsQ@„~o_ö|ø-¤¬Ì#ŸS§:AR”Eìóá°ÁŒftŒ1ÎæÕi½¶4„àz~ Ã÷[ƒ$$ÊË"wÀà£í&ë’¥3xJcn@G,¡ÙÜåÝLMá•°½ª§E½ ûo»ãŒ$al‘r£5c‰;Ñ& ^#"k¢TÜPqC¿”¿ŠÑp@­5 h¯„þ—¤q>aø'&$¼¼XžG¼Áˆ¥Þ±ó35 ZÇŽŠÚ> ÑÉ€¦ÓŽ—€ž~.ù„·ßC¡¤LG[@ëd"ˆŽ!´Aý€.A«÷%½ýáã›7ŠOþä9nÊ¢WeAÅîQ ¡zê @—«ƒ.ècØÑÝ÷~Qœ_ût´,òå1Å\O+NEÌèt®õñ¶KèÿŠÌ{U#É"4sGUC@}}gëåû»6 ÿ]¯ÆßÁ ®ˆ´4«úFŸ,û×çMýø—)̵I‘þ·:BÄ]úÁLòûÆo¡•MœÕ‹ïjDϼ)6¹,qµ4_Çõ–3Éëáý xßÿt×ji¿P!bÁ!ðZØ6&Ä™I;-sB„#úË7?Š–ö$_ `çéêÀÿÕÐB}Ú,B;]øb@øœ¸^ú?‚’îîÉ$%ƒ2‚BŽÿ_ëõË·}+6Þ°> Ð)ëXN—µûE"¥¢¤ûz@v¾öÔ²¼›Û¯ßmOéé HAA•KÇuŸ|ýªT@˯ì͉ä4ï$®ã½Ï”¬Ý¬PÞ¼yôpc¤[Ë"NYv–!Y#¨Ü9bº¦îbáÐ. í}ÄbÕÌ)G–î¾úÔYbbí.’ªFDvPð ¶kÈÔ¢,Y,rÆ:©Ú†Š u’erñ¾e?®Æf?üªFÐ~9l©ªDœ° .¶Ke:ÙÂNiéªÛÅÂ/’|±,Æ›ÏP Š,„Ú^¨<"þEÆ’ú"$…Ïrü ÕÝ®›–Œ,h¿ÜÒáw–“²X„N « ŸBÑ3A%o¡òIœrQD[Ì]2‹_z¥_å)\(f©ZÕ0¸&=|úU3¸t{ÿþ“ü¦Þ=€è¡ÖÂ`¸ç¢‡¶úr±³L6 ÍÕâ·d-ïxM¡O'oáŒ,Ê”-Pá.¢LfIÊÒ«s&Mõdç”ʾyóü¿þûù³û®»›Îíí›G?CñJ·/y=‡·A@ ]mæéL@–½geºËE¶íÇ-a²qúâÛ ‰Y,e²U–ò;qAÔíƒ(Êérá•WË,iVduδjÑAÅDµÜvëöÃc€þíx@}4' Û^´ŒlæØ„Yž8†+sšc( \VaÝ ,‡•yEP,±åI½‹0_Ú²*d)%*ú\À“·‹8‘qåÑó 4ÞD–"A,­ò¨ÖAS}ñúõ¿ÿÇþîÏ_¿ú©=ËqûìÅ·úÑý€Ôìjw2µš§­å óBÌ‡Ž J#;ŠmæÛAÉ£ƒŸfðQK±Ÿ"î«‘:vÚö:ñJa²AÄsžBIs«ÕÊÍ”󆛼]0 ×áͨx (ØD¨€P«<¥ÛÀ•üá³´Ž"ßs]ÇqWß5x¾ùó¯!µ,ƪþj·ßJÕŠ’öc3‚ÂJl¹¤8XãõÉchý–pTÂ1tUJaÝPÂ#%F%YÉóÀ9q­®Oý<ó–l‡ÅQ°tù˜ óªž?ýF ³;íˆ …bPuÛ‚8 ¾5;ñšQîÐÀ°<æƒi!aª!<Ä—8 …¡Oª±}õ±; ¡ˆ%¿rø~ßǪ€»ûão9OðÙQ5…Y? öý<€xY€Š8ðPg„Èc( lH‰ ]q'D¨$Õvgâ$åiV6É¡f·¾xðq’m‘¨È¢À‘òî^Ïó?ü¾Âƒ¥O÷ 61²»jVÏÍAС ÏI©ã$4‚háÇPà(2¹¥Âø$󜤀’-Z–"‚XD"zš›…"¶úáÃmøx¼mì-@bÆP¬Óoþø‚ÓY®>Àp%UÑb‰qÄÊ­¸Ù‰8æ€4Úä1q‡‰ U²Gˆ­8 -:â3 DOd£þ—…KwÿpD'ˆæ¿çqàËe‘Ö›ðþÕ5…H0Vƒ=WȲ‘š#¥—šÌᇼœ®‚ŸˆÖÞÕ„Vö'qP¶ÉšáU=X:¦â"ª9¿xüÔq=Þž“eÛ•ÅI3êj+ï  ÙÔ gPøaR›kHáj°sè~ûÛªâ~rÌÞÀ¡âœ_MÕòyd1hŽ;WÈ*Ošf³y{§¹âQ÷T¹m ºÀÖ»÷÷u·äŸ–¬Y²Tpâù¤ ºÊù ®…FsíѦ@ hÛ8À´IÔzù 52öã?FãZ², ZkŠ¬Þ ^=õMyï\z¸ñX»pÛÊxäœwS¶IýƒÜ12*_ñi¸÷3Z:NyÏ»p±Ç»ZT]ý}’³dÔeWvÂRà³:—ZúlNõy7¼î®Íþ&Š¢fg ‘”Åàs…+K­™õ´Ïì—^}õìYµ>ûô£b¤ý[ >êºNÄ`Ûá¾™†€ì™õ¬ýµ Éëz/T3áî÷ô]?eÉ([¸øìlt$è³¾Õóbåïç7á7Ðïxc˜ÇÖÅùˆœ˜­£€#?jtÐêßb£G7áwßóBîö·ðª¡wýH#rÎÁãž$Rs Çym]Ä ·âk ¨›÷cà³zÂý]௄iâå^´f™ba?SxÄ\ÜÐ=ªPK_Ü„¾u½ç@¿ñ…q³ð…rnqS—ጤLROõ9°±¹GuZ¯„«Äù WuRmµ+e$yì“ÃÍ0'H ;œÎP<½> z%\ Î硘Öxt{óÄs[Õ¹¥qF¿ðE+§§¹ áæ¬‚8ãvqq‹Á§zõ4¡2™WÂuªø`h¹=ú•»Ñ]Š‘DIš3VBù•r Ì(pÝîà„',‡È‘p8<ç¸]Ñ}€þfê š˜ÝÀd«D²DñÙwå-ùvÚ(Ž“4å¬àP@1$q4À†ÃYÉØþ 8»Ö$|9‰WÂ5jøˆ¥Ñb¼g«Œ#Éõø†Z_¨µ9YˆÏ`‹EoDùÀpí4®P›Ï¢²tï{™’$Þšp]Êóäægq´âir¬‚sÊp¸I辦 >ÄîË*§‘úήÖÞäjé:ï›  ÎkÚæsHõdo3_ØLª Ás&’´D«Ÿ¹ çÓ`²¶¦GùŠ-Me/èd>JcœÝ€fQHG>:ãèHK>ZãèÈÒ”Æ8²u壇1ÎÅ!}ùhbŒ³ аhßÓ­tè±Æ|´Ó˜€DÓñ0 G†Ïõ:í‹¡^@Ÿ>CÔ$?þTF‚8è&ËÃæL&´b†¶b©þÃ.p´z`ø ÐæHB»:¡tÚüìq¨ÁnfêrŽÜ—sé÷~ÚD©T€¢BÛ€êÇz#H>ÞK‘ŠUo¢…yUßžz9õŒÅI@´'fh_µòY NDnDØï~eßn{AõÔAªþéÄLßÙn@Õ?é4lÇߺæè¨¶žB$\ú]_‘.4gt¬.½ªÇè€ Íei.Hs@šë‚«zŒŽ‘¤¹L§¹ Íei.Hs@šËÒ\æ2€4—¤¹ Íei.Hs@šËÒ\æ2€4—¤¹t0•5Ú£™­Žòn0ji^ë†ã¼ŒZš×ºá8fµn8λÁ¨£9­Žón0êjVëS¾Ðÿ ÀA‘¬”ã¶IEND®B`‚libfreemarker-java-2.3.19.orig/src/manual/figures/tree.png0000644000175000017500000001113311723544470023011 0ustar ebourgebourg‰PNG  IHDRÒ¿¼-rô+tEXtCreation TimeK 31 dec. 2002 00:34:42 +0100oRÀ°tIMEÒ 9**B+° pHYs  ÒÝ~ügAMA± üaúPLTEþþþüüüúúúøøøöööôôôðððîîîìììêêêäääàààÜÜÜÞÞÞæææÚÚÚÒÒÒÌÌÌÉÉÉÇÈÈÏÏÐÕÕÕÁÁÁ¸¸¸µµµ±±±ØØØââ⬭®y}PV]UZ`|€ƒ››œ©©©½½½òòòèèèNRU %)(4@ToŠk޲F^u!*4#',abd¡¡¡­¯°8=B=N`{¤Í“Äõ™Ìÿ޽íp”º-7ATX]BFICTg‘Áñ…±Ý!(.ˆµâ=Pc˜Ëþy|ÅÅÅ(,0h‹®JOT†³à*05$'+s™¿>CHFLPptx›ž¢%-6-15Xu—ÊüPSV·¸¹%*0\y•ŒºéDVi26:",6H`xx È,038;@&).«¬¯999aaa‚‚‚555ŒŒŒXXXAAA¥¥¥jjjttt•••OOOHHHžžž¶·¸Š‹Œ111ˆˆˆVVV===™™™²³´qqqpsw...ª«¬!)2œ £(1::Ma,/2““”………EEEHKO¥§¨^^^xxx§¨©OU]HNR’’’"$)&. $'msx-285:?bej4EV]ci#)1@O^~vÄZx–Y[^ÃÅÆ4EM%1fzzî™î˜é$@È$‚á¢5•I–›ÍN6›˜åHv— ‡FAŒQP ¨€rˆ^AXu7áRQQ<ñÖÏǪž«{Ž>¦{¶ùìû'¶w_½oUuUu½_‡6mÓ6mÓ6mÓÖЀØèt m‚%I’tðu ø¿k®8cù•0ž´ëõÀˆÝ×ïyrßQ‹^öß0ç! ç3ÁG_»ë¤EÈ.üÏž!‘r>̾èÂEEû×ÞGXŠtxßä?翨l÷½Œ0n—Ñø›n­-:þ¶ü´Ã› _ûléosþEÍäè· À¿P -Úù×X€õ8ºçâO/üY´pV<äE=¯Óq™Ar1÷_P%ZzǼDVÒ~™ôÄw=QñüãúᨀÆ<Ç225ëYöêq§‰V¿øòöîƒ],ZB8s‹€Öå¶ò¾çoÚ)¯öÿaîc}CÉçrqZ^À: ÀÀ͹­Åùøßý~ï«ûö]tû=/ vÅ£áìHn F9 @~¼{DðP'z#‰—ûÊÞWflÙÌgÃËð΃’ƃEcãX!ÍL ^,¤B¼—Á?ã·: J DyÜnÅyùäD&–Ê‘ö¤ÓèGN‚ª"].é¦ÅØÄüP âåÐG þIÚ9Pu@Þrp¥©èDŒX ßÈÇ@! í  4BÁHÙ‰”És,€½$7ô¨€Š +4õqTº¼w” ´.Õ¯^ƒÑJ#9ª“á‰DÒ‡jÔi CµjŠ4E¡4M‚4¡ U@¤ 6úšiŠA@mÈ+€š3)Ò‚’F3\K –HSªÄà‰¨¤)¥ HR‡¡tiDê ”n ÍH‚€ŒëÒÔ(€÷±¶eD]@ºl†’r[@:‘l„2 ¤É&(%"Ò¤ø^Òž†±ªF© oR~ÕêÈYLe@G ÉÄtQ©€Œ0„É]øaB`õæÓC!SF§Õ—xù9ï™}öŒù>þZ Âã&€·ó®œ}`å’G#º5  Ï«F§qÀ+V]qÑ곟zþ‰!ŽrÆ»Çyã@ oQF·F Ê•_uG%:uV¬|ÛRœk8ííïXJmìQFj½Ð=¨¡òtAá/ªÍ—_PV*,ýÍ®þ)F’Œ©½-|+oD÷ ‚ê]¦ß¼üüjÞîØ{†#ÑÅ­SýèÚÛìd„ñ¸ô§jP/ýZ·?@žst5»zÜœs£ÅÍycóB· Ÿ6”ª-B¹)æ1ýþ »ìÍŠø‘o‰‡†J7ÞThÝHµÞR¼Q݆"Ýþ``öYŠ?:êìdVà 'Œë¼%>Ê@Ï+B!¦P<ãMŠ?:úÚùQK”Ôz;3aF÷ Ë§ß€é§žVUýÌý•¥B·ÓY¿ )Z‡ðÓÉ“O©üÑâcfšÒ“´×®"þ é;ñKKsÒ óºL©~j½]mRCd(:àò„,<ö8Ü®‹OX’I˜ÒfÉÞ~Yòv÷’¾ùQÃ#žñè‘–¢³fÏ9ò¨£ç3/3?ðšPÐ!oÜàŸËÞ^øÅpW>ä7%!*F÷âÈßžæõ%SA-ÑA—G䓇qÄŒ7ÌìJ¤‚h7^­è;À7Ú›ùÉ9{~zøó;žNDyÖÈêA]àÙ%(ºŸmÞ0 iêB( Š£±x"CK¼â0Ñù]ÃÏB©¾‰ÁÝC#cƒæ*HŽ.M§ú“ùD²¯?Ëj\3‚¤?†‚aœ×7¥Ë‚ÂSÏùÃÁ®‰L>–:ølÈ'žãÊuä^{U8¦>⵺CLša½^ËÑæ”f€|:Çû„Ha"™ † ‡Ö²’Ié€ôhÆáy~æ¶€ŸÑ¼ëÑ -{±tÁÜ™›Ï±>_l"ÎGüÞ‘C)]›* cKå"È#Ëò¹¤¨½‚äu/6“‡$€´íi†c.:‘|"#ŒˆfÛöl§9}ÁÑ==΀¼ cv› n=’8ަ²)üÕEÆú$®¢µ§%,EJG»Ã´ÛæÓ ðÌ0ªQôý˜ˆ¢÷Òã¡·ïÀa˜™™ò9–¦e-Õ»‰6W?úKwŒúP¡ÜéÞmEÿº#;¶‹”‰2®YKѸqЫ±©—1ãË€ÁÌXŠã8ÊM’Å ä4Iº3c 3#`»£4-’B—в·ç¶¿¿HÒå*!¹\ii`T01BÀ¡g9ÔïdÁ/Anì¡í<ˆžþîviA”¶ù •ÎÚÊî.Àµî4¹ÈU‚¦šXÎOÙ(Ñ©± n$T$¬ á탭‡¢´Ñ®„þ0]nHpë7ve pjtƒIVV‘ ‘ö¡ÉÉhÝ™iºLV£—¬3Þâú ßôL ¸@E~ õwÜðäÜ›34]®ä‹ïØ6@þЈÜíH¹×W‘ð¢Øðä‚Ý]‹á^·Å®© -W·yq·“‹SfQÕ¦NNh5²¦8)Ò»ºÖûl ðrµ46€šÄ&îz''@­ï¢hEe@‚Éì €˜CËU®ú+sµ¨ëœœ@ª¸ªt4äªg£dÇàÈSa‰«”Uƒ NNx®ìw²«l7onѨ±ì蘼\-·CMF ¾†&'´Ï«ún&-kWà>xP,NIå×X-089Áäz‘VWj&[Ö®ååj¥ Z$C“þ׌P’úŵ«µ‡¼Ðd*ì(-WËe×éÊ““öPÐ)áïŽJµc Ò{gùè€8 Èñ\„c$…Ê¡N÷Pžœhœ[Ô @˹€¸Wå¶W=AkWAŒd}%½L{d9‚ÛËpŒrk©î¡491œb[ÇèÍx|ﲓï¼,ö«Fbr?~ ‹’ÚEZ‰Jb‰GÖxYQ~#ÝÞYØö}-±øƒÇŸxò”“ßøÐ¬‡ýµ;¥ÐU˜=W¯h@c•å {d"ø\Oeo¨{@µë¹îÀ;µÄ^ù{qRiÿê¾òª7#̯üž^Ñ€F¤ª¼á› âa/WîÍt¨vW^ %@kg5ýòí°OµeÜB"•çYÙJî¾i‘Õ €_{èë•$Ù-+¿¡¾^ž×B#«‘7ì–ë²ÁƒJ‘@k,Àý¥/WS™û¿òUUú¥m"„úrk=—ó»M‹Ô Œ<ðEEÂùÁ3U²€6ŠjË­ó=ØsÓ"¡Oc,phj_¼ïþB€¥*=¯­"u¹Í<ëPÛþDàžÕŠ_üüT²€öŠTHM<ÝꑤwUߥ¥wŸ[PÈÚ-BP”ÛÄ3Ðý Rú3—U/öøÜJµ, Í"e+5ñ t?¨wMFÜ^?}ÇjY@{% êr›xÖÿ Îµ‹úÄ'?uË~Üën½­VÐ^Iƒª{ Ï7ÜØÀsÓ"5ǂּ\ô#{?ºïcŸsÓÍ™¤Z´Ð^IƒºÜ4wÝû?€=ïù༾d¬ì¹i‘ÚcA‹A–¿øC˯¿áÃ×mHÄjròm•4¨Ë%é«Þwõé×1ãÚ I…¡i‘šcAŸ‹4 Æó,Z=êÏÚvJTåº"Ýqä¸ìß­”#4-R{,¨A)ÑϲÙl€÷ÖæÐÛ*iP;Øë„ƒÙhêÊ•¡i‘ÚcÁ¢Iôùý~_ƒ|s% j¿éÞMŒ×ï„ÈðhX`Ó"µÇ‚¿ëݲ®}Ø×ý^û$ j·¡î'2Ç1á\‚U‡Þ¬Hí±ù޲‰º]’†š"GÖP–^£ëäM‹ÔËäGÚ"i¨q)m+à-6|¯HIŽ ~‡›iA,íB*‹pž»r ˆ*b\ë®ÌfÖf9‚H¾²AN‰ysy“ÂÖœÙ+U“ÂrÎÇáW´²wR&…圳‘‚ݺ*6å|¬$“’:)ìôBž”he6ÉñDyRªI ;x€¨LJÕ…ªÓå¤T2§ªI©DéìB=)Uœ<@ÔLJ¥Ú¦±OJXã¬nŠjÄq—ñãM.—¤ºÑ Tï0–wú>+½@$`9aèÚ.†z^ßfú=¤î­#*fЗÏã½òÙõC‚ÌîZ€Óå·=uoP9Q¾óÒSBÝ@ÄWY“º·I™(_á•j¶Ja^ÿyÿN©åaŸzCÛºÔ½uV“(Šˆª|¸u©{ˬ.®>ˆi]êÞ:k‘›·.uo!ÒäùpëR÷"Mž·.uo™µÈ‡[—º·ÐZäíKÝ[ˆ4y>ܺԽuÖ"n]êÞB¤ÉóáŠÇ—^6¯oHÛyÿ[‹|xõñ{wlÊgð]j‘/?ÎÛcYÞç€5^«|xùq(;˜Kñ~iª¿Iå 'ˇûüB`[Ÿàˆ‹ÃZæÃåÇÍ1[P#: ßÉAOž/_-èš½ÁV¨Ióáò Ò³n‹É˦–ášö@´Éð Ä„c÷’j¦µkº—Ü É¶ˆ629<ÙÔÉÙɦ&HNN65frz6º "¯·©‰ÞÜ'_`ÑéHÚfvQ¶Éöëu,g²ýzë‘l¿^Çz³ûz 5“­×ëØƒÄwg‹t:–¶1é5k9ÃwxOELä"ᬳt­ïz·³t­ˆø*M×8Çà Çé Z˜u-Ì:ˆæDD s¢¢’u­œ§ƒhaŽÔA´0'ê Z!9PÑœ¨ƒh…dÙ3ë®0è˜Yw…A™¬ºÂ ³L–\aÐQ&k®0è,“WtÚ¦îµÓ6mí³ÿ%¨^uóYßKIEND®B`‚libfreemarker-java-2.3.19.orig/src/manual/book.xml0000644000175000017500000434157611723544471021402 0ustar ebourgebourg FreeMarker Manual For FreeMarker 2.3.19 Preface
What is FreeMarker? FreeMarker is a template engine: a generic tool to generate text output (anything from HTML to autogenerated source code) based on templates. It's a Java package, a class library for Java programmers. It's not an application for end-users in itself, but something that programmers can embed into their products. FreeMarker is designed to be practical for the generation of HTML Web pages, particularly by servlet-based applications following the MVC (Model View Controller) pattern. The idea behind using the MVC pattern for dynamic Web pages is that you separate the designers (HTML authors) from the programmers. Everybody works on what they are good at. Designers can change the appearance of a page without programmers having to change or recompile code, because the application logic (Java programs) and page design (FreeMarker templates) are separated. Templates do not become polluted with complex program fragments. This separation is useful even for projects where the programmer and the HTML page author is the same person, since it helps to keep the application clear and easily maintainable. Although FreeMarker has some programming capabilities, it is not a full-blown programming language like PHP. Instead, Java programs prepare the data to be displayed (like issue SQL queries), and FreeMarker just generates textual pages that display the prepared data using templates. FreeMarker is not a Web application framework. It is suitable as a component in a Web application framework, but the FreeMarker engine itself knows nothing about HTTP or servlets. It simply generates text. As such, it is perfectly usable in non-web application environments as well. Note, however, that we provide out-of-the-box solutions for using FreeMarker as the view component of Model 2 frameworks such as Struts. FreeMarker is Free, released under a BSD-style license. It is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative.
What should I read? If you are a ... designer, then you should read the and then you can look into the on an as-needed basis for more specific details. programmer, then you should read the guide first, then the and then you can look into the on an as-needed basis for more specific details.
Document conventions Variable names, template fragments, Java class names, etc. are written like this: foo. If something should be replaced with a concrete value then it is written in italics, as follows: Hello yourName!. Template examples are written like this: something Data-model examples are written like this: something Output examples are written like this: something Program examples are written like this: something This paragraph is for the editors, and not visible for the public In chapters this section is for the editors toowritten for both designers and programmers fragments addressed to programmers are written like this: This is for programmers only. New terms are emphasized like this: some new term
Contact help homepage download contact For the latest version of FreeMarker and to subscribe to the mailing lists visit the FreeMarker homepage: If you need help or you have suggestions, use the mailing lists (mail archives can be searched without subscription) or the Web based forums. If you want to report a bug, use the Web based bug tracker, or the mailing lists. To find all of these visit . Also, note that we have a FAQ and index; use them.
About this document If you find any mistakes (including grammatical mistakes, typos, typographical mistakes) or you find something misleading or confusing in the documentation, or you have other suggestions, please let me know! Email: ddekany at users.sourceforge.net
Template Author's Guide Getting Started This chapter is a very rough introduction to FreeMarker. The chapters after this will go over things in much greater detail. Nonetheless, once you have read this chapter, you will be able to write simple but useful FreeMarker templates.
Template + data-model = output Assume you need a HTML page in an e-shop application, similar to this: <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome Big Joe!</h1> <p>Our latest product: <a href="products/greenmouse.html">green mouse</a>! </body> </html> Let's say that the user name ("Big Joe" above) should depend on who the logged in Web page visitor is, and the latest product should come from a database and thus it potentially changes at any moment. In this situation you can't just enter the user name nor the URL and name of the latest product into the HTML, you can't use static HTML. FreeMarker's solution for this problem is using a template instead of the static HTML. The template is the same as the static HTML, except that it contains some instructions to FreeMarker that makes it dynamic: <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome ${user}!</h1> <p>Our latest product: <a href="${latestProduct.url}">${latestProduct.name}</a>! </body> </html> The template is stored on the Web server, usually just like the static HTML page would be. But whenever someone visits this page, FreeMarker will step in and transform the template on-the-fly to plain HTML by replacing the ${...}-s with up-to-date content (e.g., replacing ${user} with Big Joe or whoever the visitor is) and send the result to the visitor's Web browser. So the visitor's Web browser will receive something like the first example HTML (i.e., plain HTML without FreeMarker instructions), and it will not perceive that FreeMarker is used on the server. The template file itself (which is, again, stored on the Web server) is not changed during this, so the transformation will happen again and again for each visiting. This ensures that the displayed information is always up-to-date. Now, you already may have noticed that the template contains no instructions regarding how to find out who the current visitor is, or how to query the database to find out what the latest product is. It seems it just already know these values. And indeed that's the case. An important idea behind FreeMarker (actually, behind Web MVC) is that presentation logic and "business logic" should be separated. In the template you only deal with presentation issues, that is, visual design issues, formatting issues. The data that will be displayed (such as the user name and so on) is prepared outside FreeMarker, usually by routines written in Java language or other general purpose language. So the template author doesn't have to know how these values are calculated. In fact, the way these values are calculated can be completely changed while the templates can remain the same, and also, the look of the page can be completely changed without touching anything but the template. This separation can be especially useful when the template authors (designers) and the programmers are different individuals. data-model While for FreeMarker (and for the template author) it's not interesting how the data was calculated, FreeMarker still have to know what the actual data is. All the data that the template can use is packed into the so called data-model. It's created by the already mentioned routines that calculate the data. As far as the template author is concerned, the data-model is a tree-like structure (like folders and files on your hard disk), that in this case could be visualized as: (root) | +- user = "Big Joe" | +- latestProduct | +- url = "products/greenmouse.html" | +- name = "green mouse" (To prevent misunderstandings: The data-model is not a text file, the above is just a visualization of a data-model for you. It's from Java objects, but let that be the problem of the Java programmers.) Compare this with what you seen in the template earlier: ${user} and ${latestProduct.name}. As an analogy, the data model is something like the file system of computers: the root and latestProduct correspond to directories (folders) and the user, url and name correspond to files. url and name are in the latestProduct directory. So latestProduct.name is like saying name in the latestProduct directory. But as I said, it was just a simile; there are no files or directories here. To recapitulate, a template and a data-model is needed for FreeMarker to generate the output (like the HTML shown first): Template + data-model = output
The data-model at a glance As you have seen, the data-model is basically a tree. This tree can be arbitrarily complicated and deep, for example: (root) | +- animals | | | +- mouse | | | | | +- size = "small" | | | | | +- price = 50 | | | +- elephant | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- python | | | +- size = "medium" | | | +- price = 4999 | +- test = "It is a test" | +- whatnot | +- because = "don't know" The variables that act as directories (the root, animals, mouse, elephant, python, whatnot) are called hashes. Hashes store other variables (the so called subvariables) by a lookup name (e.g., "animals", "mouse" or "price"). The variables that store a single value (size, price, test and because) are called scalars. When you want to use a subvariable in a template, you specify its path from the root, and separate the steps with dots. To access the price of a mouse, you start from the root and go into animals, and then go into mouse then go into price. So you write animals.mouse.price. When you put the special ${...} codes around an expression like this, you are telling FreeMarker to output the corresponding text at that point. There is one more important kind of variable: sequences. They are similar to hashes, but they don't store names for the variables they contain. Instead, they store the subvariables sequentially, and you can access them with a numerical index. For example, in this data-model, animals and whatnot.fruits are sequences: (root) | +- animals | | | +- (1st) | | | | | +- name = "mouse" | | | | | +- size = "small" | | | | | +- price = 50 | | | +- (2nd) | | | | | +- name = "elephant" | | | | | +- size = "large" | | | | | +- price = 5000 | | | +- (3rd) | | | +- name = "python" | | | +- size = "medium" | | | +- price = 4999 | +- whatnot | +- fruits | +- (1st) = "orange" | +- (2nd) = "banana" To access a subvariable of a sequence you use a numerical index in square brackets. Indexes start from 0 (it's a programmer tradition to start with 0), thus the index of the first item is 0, the index of the second item is 1, and so on. So to get the name of the first animal you write animals[0].name. To get the second item in whatnot.fruits (which is the string "banana") you write whatnot.fruits[1]. Scalars can be further divided into these categories: String: Text, that is, an arbitrary sequence of characters such as ''m'', ''o'', ''u'', ''s'', ''e'' above. For example the name-s and size-s are strings above. Number: It's a numerical value, like the price-s above. The string "50" and the number 50 are two totally different things in FreeMarker. The former is just a sequence of two characters (which happens to be readable as a number for humans), while the latter is a numerical value that you can use, say, in arithmetical calculations. Date/time: A date or time. Like the date an animal were captured, or the time the shop opens. Boolean: A true/false (yes/no, on/off, etc.) thing. Like animals could have a protected subvariable, which store if the animal is protected or not. Summary: The data-model can be visualized as a tree. Scalars store a single value. The value can be a string or a number or a date/time or a boolean. Hashes are containers that store other variables and associate them with a unique lookup name. Sequences are containers that store other variables in an ordered sequence. The stored variables can be retrieved via their numerical index, starting from 0.
The template at a glance The simplest template is a plain HTML file (or whatever text file -- FreeMarker is not confined to HTML). When the client visits that page, FreeMarker will send that HTML to the client as is. However if you want that page to be more dynamic then you begin to put special parts into the HTML which will be understood by FreeMarker: ${...}: FreeMarker will replace it in the output with the actual value of the thing inside the curly brackets. They are called interpolations. As an example see the very first example. FTL tags (for FreeMarker Template Language tags): FTL tags are a bit similar to HTML tags, but they are instructions to FreeMarker and will not be printed to the output. The name of these tags start with #. (User-defined FTL tags use @ instead of #, but they are an advanced topic.) Comments: Comments are similar to HTML comments, but they are delimited by <#-- and -->. Anything between these delimiters and the delimiter itself will be ignored by FreeMarker, and will not be written to the output. Anything not an FTL tag or an interpolation or comment is considered as static text, and will not be interpreted by FreeMarker; it is just printed to the output as is. With FTL tags you refer to so-called directives. This is the same kind of relationship as between HTML tags (e.g.: <table> and </table>) and HTML elements (e.g., the table element) to which you refer to with the HTML tags. (If you don't feel this difference then just take "FTL tag" and "directive" as synonyms.)
Examples of directives Though FreeMarker has far more directives, in this quick overview we will only look at three of the most commonly used ones.
The if directive With the if directive you can conditionally skip a section of the template. For example, assume that in the very first example you want to greet your boss, Big Joe, differently from other users: <html> <head> <title>Welcome!</title> </head> <body> <h1> Welcome ${user}<#if user == "Big Joe">, our beloved leader</#if>! </h1> <p>Our latest product: <a href="${latestProduct.url}">${latestProduct.name}</a>! </body> </html> Here you have told FreeMarker that the '', our beloved leader'' should be there only if the value of the variable user is equal to the string "Big Joe". In general, things between <#if condition> and </#if> tags are skipped if condition is false (the boolean value). Let's detail the condition used here: The == is an operator that tests if the values at its left and right side are equivalent, and the results is a boolean value, true or false accordingly. On the left side of == I have referenced a variable with the syntax that should be already familiar; this will be replaced with the value of the variable. In general, unquoted words inside directives or interpolations are treated as references to variables. On the right side I have specified a literal string. Literal strings in templates must always be put inside quotation marks. This will print "Pythons are free today!" if their price is 0: <#if animals.python.price == 0> Pythons are free today! </#if> Similarly as earlier when a string was specified directly, here a number is specified directly (0). Note that the number is not quoted. If you quoted it ("0"), FreeMarker were misinterpret it as a string literal. This will print "Pythons are not free today!" if their price is not 0: <#if animals.python.price != 0> Pythons are not free today! </#if> As you may have guessed, != means not equivalent. You can write things like this too (using the data-model used to demonstrate hashes): <#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. </#if> With the <#else> tag you can specify what to do if the condition is false. For example: <#if animals.python.price < animals.elephant.price> Pythons are cheaper than elephants today. <#else> Pythons are not cheaper than elephants today. </#if> This prints ''Pythons are cheaper than elephants today.'' if the price of python is less than the price of elephant, or else it prints ''Pythons are not cheaper than elephants today.'' If you have a variable with boolean value (a true/false thing) then you can use it directly as the condition of if: <#if animals.python.protected> Warning! Pythons are protected animals! </#if>
The list directive This is useful when you want to list something. For example if you merge this template with the data-model I used earlier to demonstrate sequences: <p>We have these animals: <table border=1> <tr><th>Name<th>Price <#list animals as being> <tr><td>${being.name}<td>${being.price} Euros </#list> </table> then the output will be: <p>We have these animals: <table border=1> <tr><th>Name<th>Price <tr><td>mouse<td>50 Euros <tr><td>elephant<td>5000 Euros <tr><td>python<td>4999 Euros </table> The generic format of the list directive is: <#list sequence as loopVariable>repeatThis</#list> The repeatThis part will be repeated for each item in the sequence that you have given with sequence, one after the other, starting from the first item. In all repetitions loopVariable will hold the value of the current item. This variable exists only between the <#list ...> and </#list> tags. As another example, we list the fruits of that example data model: <p>And BTW we have these fruits: <ul> <#list whatnot.fruits as fruit> <li>${fruit} </#list> <ul> The whatnot.fruits expression should be familiar to you; it references a variable in the data-model.
The include directive With the include directive you can insert the content of another file into the template. Suppose you have to show the same copyright notice on several pages. You can create a file that contains the copyright notice only, and insert that file everywhere where you need that copyright notice. Say, you store this copyright notice in copyright_footer.html: <hr> <i> Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, <br> All Rights Reserved. </i> Whenever you need that file you simply insert it with the include directive: <html> <head> <title>Test page</title> </head> <body> <h1>Test page</h1> <p>Blah blah... <#include "/copyright_footer.html"> </body> </html> and the output will be: <html> <head> <title>Test page</title> </head> <body> <h1>Test page</h1> <p>Blah blah... <hr> <i> Copyright (c) 2000 <a href="http://www.acmee.com">Acmee Inc</a>, <br> All Rights Reserved. </i> </body> </html> If you change the copyright_footer.html, then the visitor will see the new copyright notice on all pages.
Using directives together You can use directives as many times on a page as you want, and you can nest directives into each other similarly as you can nest HTML elements into each other. For example this will list the animals and print the name of large animals with bigger font: <p>We have these animals: <table border=1> <tr><th>Name<th>Price <#list animals as being> <tr> <td> <#if being.size == "large"><font size="+1"></#if> ${being.name} <#if being.size == "large"></font></#if> <td>${being.price} Euros </#list> </table> Note that since FreeMarker does not interpret text outside FTL tags, interpolations and comments, it doesn't see the above font tags as badly nested ones.
Dealing with missing variables In practice the data-model often has variables that are optional (i.e., sometimes missing). To spot some typical human mistakes, FreeMarker doesn't tolerate the referring to missing variables unless you tell them explicitly what to do if the variable is missing. Here we will show the two most typical ways of doing that. Note for programmers: A non-existent variable and a variable with null value is the same for FreeMarker, so the "missing" term used here covers both cases. Wherever you refer to a variable, you can specify a default value for the case the variable is missing, by following the variable name with a ! and the default value. Like in the following example, when user is missing from data model, the template will behave like if user's value were the string "Anonymous". (When user isn't missing, this template behaves exactly like if !"Anonymous" were not there): <h1>Welcome ${user!"Anonymous"}!</h1> You can ask whether a variable isn't missing by putting ?? after its name. Combining this with the already introduced if directive you can skip the whole greeting if the user variable is missing: <#if user??><h1>Welcome ${user}!</h1></#if> Regarding variable accessing with multiple steps, like animals.python.price, writing animals.python.price!0 is correct only if animals.python is never missing and only the last subvariable, price, is possibly missing (in which case here we assume it's 0). If animals or python is missing, the template processing will stop with an "undefined variable" error. To prevent that, you have to write (animals.python.price)!0. In that case the expression will be 0 even if animals or python is missing. Same logic goes for ??; animals.python.price?? versus (animals.python.price)??.
Values, Types
Basics It is assumed that you have already read the chapter. Understanding the concept of values and types is crucial for the understanding of data-models. However, the concept of values and types is not confined to data-models, as you will see.
What is a value? value Real programmers can safely skip this section. Examples of values as you know the term from the everyday math are 16, 0.5, and so on, i.e. numbers. In the case of computer languages the value term has a wider meaning, as a value needn't be a number. For example, take this data-model: (root) | +- user = "Big Joe" | +- today = Jul 6, 2007 | +- todayHoliday = false | +- lotteryNumbers | | | +- (1st) = 20 | | | +- (2st) = 14 | | | +- (3rd) = 42 | | | +- (4th) = 8 | | | +- (5th) = 15 | +- cargo | +- name = "coal" | +- weight = 40 We say that the value of the the user variable is "Big Joe" (a string), the value of today is Jul 6, 2007 (a date), the value of todayHoliday is false (a boolean, ie. a yes/no thing). The value of lotteryNumbers is the sequence that contains 20, 14, 42, 8, 15. Surely lotteryNumbers is multiple values in the sense that it contains multiple values (for example, the 2nd item in it is a the value 14), but still, lotteryNumbers itself is a single value. It's like a box that contains many other items; the whole box can be seen as a single item. Last not least we also have the value of cargo, which is a hash (a box-like thing again).So, a value is something that can be stored in a variable (e.g., in user or cargo or cargo.name). But a value need not be stored in a variable to be called a value, for example we have the value 100 here: <#if cargo.weight < 100>Light cargo</#if> The temporaly result of a calculations are also called values, like 20 and 120 when this template is executed (it will print 120): ${cargo.weight / 2 + 100} Explanation for this last: As the result of dividing the two values, 40 (the weight of the cargo) and 2, a new value 20 is created. Then 100 is added to it, so the value 120 is created. Then 120 is printed (${...}), and the template execution goes on and all these values gone. Certainly now you feel what the value term means.
What is type? Values have an important aspect, their type. For example the type of the value of the user variable is string, and the type of the value of the lotteryNumbers variable is sequence. The type of a value is important because it determines to a large extent how and where you can use the value. Like ${user / 2} is an error, but ${cargo.weight / 2} works and prints 20, since division only does make sense for a number, but not for a string. Or, using dot like in cargo.name does make sense only if cargo is a hash. Or, you can list with <#list ...> sequences only. Or, the condition of <#if ...> must be a boolean. And so on. A little terminology... Saying "a boolean" or "a boolean value" or "a value of type boolean" are all the same. Multi-typed value A value can have multiple types at the same time, although it's rarely utilized. For example in the data-model below mouse is both a string and a hash: (root) | +- mouse = "Yerri" | +- age = 12 | +- color = "brown" If you merge this template with the above data-model: ${mouse} <#-- uses mouse as a string --> ${mouse.age} <#-- uses mouse as a hash --> ${mouse.color} <#-- uses mouse as a hash --> the output will be: Yerri 12 brown
The data-model is a hash Looking at the various data-model examples you may already realized: the thing marked as "(root)" is just a value of type hash. When you write something like user, that means that you want the "user" variable stored in the root hash. Like if you were writing root.user, except that there is no variable called "root" so that wouldn't work. Some may get confused by the fact that our example data-model, that is, the root hash, contains further hashes and sequences (lotteryNumbers and cargo). There is nothing special in that. A hash contains other variables, and those variables have a value, which can be a string, a number, etc., and of course it can be a hash or sequence as well. Because, as it was explained earlier, a sequence or a hash is just a value, like a string or a number is.
The types The suppored types are: Scalars: String Number Boolean Date Containers: Hash Sequence Collection Subroutines: Methods and functions User-defined directives Miscellaneous/seldom used: Node
Scalars These are the basic, simple kind of values. They can be: string the FTL value type String: It is simple text, e.g., the name of a product. If you want to give a string value directly in the template, rather than use a variable that comes from the data model, you write the text between quotation marks, e.g., "green mouse" or 'green mouse'. (More details regarding the syntax can be found later.) number the FTL value type Number: For example the price of a product. Whole numbers and non-whole numbers are not distinguished; there is only a single number type. So for example 3/2 will be always 1.5, and never 1. Just like if you are using a calculator. If you want to give a numerical value directly in the template, then you write for example: 150 or -90.05 or 0.001. (More details regarding the syntax can be found later.) boolean the FTL value type Boolean: A boolean value represents a logical true or false (yes or no). For example, if a the visitor has been logged in or not. Typically you use booleans as the condition of the if directive, like <#if loggedIn >...</#if> or <#if price == 0>...</#if>; in the last case the result of the price == 0 part is a boolean value. In the templates you can directly specify a boolean with the reserved words true and false. date the FTL value type time the FTL value type date-time the FTL value type Date: A date variable stores date/time related data. It has three variations: A date with day precision (often referred simply as "date") as April 4, 2003 Time of day (without the date part), as 10:19:18 PM. Time is stored with millisecond precision. Date-time (sometimes called "time stamp") as April 4, 2003 10:19:18 PM. The time part is stored with millisecond precision. Unfortunately, because of the limitations of the Java platform, FreeMarker sometimes can't decide which parts of the date are in use (i.e., if it is date-time, or a time of day, etc.). The solution for this problem is an advanced topic that will be discussed later. It is possible to define date values directly in templates, but this is an advanced topic that will be explained later. Bear in mind that FreeMarker distinguishes strings from numbers and booleans, so the string "150" and the number 150 are totally different. A number holds a numerical value. A boolean holds a logical true or false. A string holds an arbitrary sequence of characters.
Containers Re-explanation of hashes and sequences from a more ''professional'' viewpoint as earlier, and some meditation about them. These are the values whose purpose is to contain other variables; they are just containers. The contained variables are often referred as subvariables. The container types are: hash the FTL value type Hash: Associates a unique lookup name with each of its subvariables. The name is an unrestricted string. A hash doesn't define an ordering for the subvariables in it. That is, there is no such thing as the first subvariable, and the second subvariable, etc.; the variables are just accessed by name. sequence the FTL value type Sequence: Associates an integer number with each of its subvariables. The first subvariable is associated with 0, the second with 1, the third to 2, and so on; the subvariables are ordered. These numbers are often called the indexes of the subvariables. Sequences are usually dense, i.e., all indexes up to the index of the last subvariable have an associated subvariable, but it's not strictly necessary. The type of the subvariable values need not be the same. collection the FTL value type Collection: A collection, from the viewpoint of the template author, is a restricted sequence. You cannot access its size or retrieve its subvariables by index, but they can be still listed with the list directive. Note that since a value can have multiple types, it is possible for a value to be both a hash and a sequence, in which case it would support index-based access as well as access by lookup name. However, typically a container will be either a hash or a sequence, not both. As the value of the variables stored in hashes and sequences (and collections) can be anything, it can be a hash or sequence (or collection) as well. This way you can build arbitrarily deep structures. The data-model itself (or better said the root of it) is a hash.
Subroutines
Methods and functions method the FTL value type A value that is a method or a function is used to calculate another value, influenced by the parameters you give to it. For programmer types: Methods/functions are first-class values, just like in functional programming languages. This means that functions/methods can be the parameters or return values of other functions/methods, you can assign them to variables, and so on. Suppose that programmers have put the method variable avg in the data-model that can be used to calculate the average of numbers. If you give the 3 and 5 as parameters when you access avg, then you get the value 4. The usage of methods will be explained later, but perhaps this example helps to understand what methods are: The average of 3 and 5 is: ${avg(3, 5)} The average of 6 and 10 and 20 is: ${avg(6, 10, 20)} The average of the price of a python and an elephant is: ${avg(animals.python.price, animals.elephant.price)} this will output: The average of 3 and 5 is: 4 The average of 6 and 10 and 20 is: 12 The average of the price of a python and an elephant is: 4999.5 What is the difference between a method and a function? As far as the template author is concerned, nothing. Well not really nothing, as methods typically come from the data-model (as they reflect the methods of Java objects), and functions are defined in templates (with the function directive -- an advanced topic), but both can be used on the same way.
User-defined directives macro the FTL value type directive the FTL value type user-defined directive the FTL value type A value of this type can be used as user-defined directive (with other words, as FreeMarker tag). An user-defined directive is a subroutine, something like a little reusable template fragment. But this is an advanced topic that will be explained later in its own chapter. For programmer types: user-defined directives (such as macros), are first-class values too, just like functions/methods are. Just to get an idea about user-defined directives (so just ignore this if you won't understand), assume we have a variable, box, whose value is a user-defined directive that prints some kind of fancy HTML message box with a title bar and a message in it. The box variable could be used in the template like this (for example): <@box title="Attention!"> Too much copy-pasting may leads to maintenance headaches. </@box>
Function/method versus user-defined directive This is for advanced users again (so ignore it if you don't understand). It's a frequent dilemma if you should use a function/method or an user-defined directive to implement something. The rule of thumb is: Implement the facility as user-defined directive instead of as function/method if: ... the output (the return value) is markup (HTML, XML, etc.). The main reason is that the result of functions are subject to automatic XML-escaping (due to the nature of ${...}), while the output of user-defined directives are not (due to the nature of <@...>; its output is assumed to be markup, and hence already escaped). ... it's the side-effect that is important and not the return value. For example, a directive whose purpose is to add an entry to the server log is like that. (In fact you can't have a return value for a user-defined directive, but some kind of feedback is still possible by setting non-local variables.) ... it will do flow control (like for example list or if directives do). You just can't do that with a function/method anyway. The Java methods of FreeMarker-unaware Java objects are normally visible as methods in templates, regardless of the nature of the Java method. That said, you have no choice there.
Miscellaneous
Nodes node the FTL value type Node variables represent a node in a tree structure, and are used mostly with XML processing, which is an advanced, and specialized topic. Still, a quick overview for advanced users: A node is similar to a sequence that stores other nodes, which are often referred as the children nodes. A node stores a reference to its container node, which is often referred as the parent node. The main point of being a node is the topological information; other data must be stored by utilizing that a value can have multiple types. Like, a value may be both a node and a number, in which case it can store a number as the "pay-load". Apart from the topological information, a node can store some metainformation as well: a node name, a node type (string), and a node namespace (string). For example, if the node symbolizes a h1 element in an XHTML document, then its name could be "h1", it's node type could be "element", and it's namespace could be "http://www.w3.org/1999/xhtml". But it's up to the designer of the data-model if what meaning these metainformations have, and if they are used at all. The way of retrieving the topological and metainformations is described in a later chapter (that you don't have to understand at this point).
The Template template It is assumed that you have already read the and the chapter.
Overall structure Templates are in fact programs you write in a language called FTL FTL (for FreeMarker Template Language). This is a quite simple programming language designed for writing templates and nothing else. A template (= FTL program) is a mix of the following sections: Text text : Text that will be printed to the output as is. Interpolation interpolation : These sections will be replaced with a calculated value in the output. Interpolations are delimited by ${ and } (or with #{ and }, but that shouldn't be used anymore; see more here). FTL tags FTL tag : FTL tags are a bit similar to HTML tags, but they are instructions to FreeMarker and will not be printed to the output. Comments comment <#--...--> # : Comments are similar to HTML comments, but they are delimited by <#-- and -->. Comments will be ignored by FreeMarker, and will not be written to the output. Let's see a concrete template. I have marked the template's components with colors: text, interpolation, FTL tag, comment. With the [BR]-s I intend to visualize the line breaks. <html>[BR] <head>[BR]   <title>Welcome!</title>[BR] </head>[BR] <body>[BR]   <#-- Greet the user with his/her name -->[BR]   <h1>Welcome ${user}!</h1>[BR]   <p>We have these animals:[BR]   <ul>[BR]   <#list animals as being>[BR]     <li>${being.name} for ${being.price} Euros[BR]   </#list>[BR]   </ul>[BR] </body>[BR] </html> FTL distinguishes upper case and lower case letters. So list is good directive name, while List is not. Similarly ${name} is not the same as ${Name} or ${NAME} It is important to realize that interpolations can be used in text (and in string literal expressions; see later) only. An FTL tag can't be inside another FTL tag nor inside an interpolation. For example this is WRONG: <#if <#include 'foo'>='bar'>...</#if> Comments can be placed inside FTL tags and interpolations. For example: <h1>Welcome ${user <#-- The name of user -->}!</h1>[BR] <p>We have these animals:[BR] <ul>[BR] <#list <#-- some comment... --> animals as <#-- again... --> being>[BR] ... For those of you who have tried the above examples: You may notice that some of spaces, tabs and line breaks are missing from the template output, even though we said that text is printed as is. Don't bother with it now. This is because the feature called ''white-space stripping'' is turned on, and that automatically removes some superfluous spaces, tabs and line breaks. This will be explained later.
Directives <#...> # Note that the Expressions chapter depends on this chapter, and Interpolations chapter depends on Expressions chapter. Thus Directives must be the first chapter after Basics. directive You use FTL tags to call directives. In the example you have called the list directive. Syntactically you have done it with two tags: <#list animals as being> and </#list>. FTL tag There are two kind of FTL tags: Start-tag: <#directivename parameters> End-tag: </#directivename> This is similar to HTML or XML syntax, except that the tag name starts with #. If the directive doesn't have nested content (content between the start-tag and the end-tag), you must use the start-tag with no end-tag. For example you write <#if something>...</#if>, but just <#include something> as FreeMarker knows that the include directive can't have nested content. The format of the parameters depends on the directivename. In fact there are two types of directives: predefined directives and user-defined directives. For user-defined directives you use @ instead of #, for example <@mydirective parameters>...</@mydirective>. Further difference is that if the directive has no nested content, you must use a tag like <@mydirective parameters />, similarly as in XML (e.g. <img ... />). But user-defined directives is an advanced topic that will be discussed later. FTL tags, like HTML tags, must be properly nested. So the code below is wrong, as the if directive is both inside and outside of the nested content of the list directive: <ul> <#list animals as being> <li>${being.name} for ${being.price} Euros <#if user == "Big Joe"> (except for you) </#list> <#-- WRONG! The "if" has to be closed first. --> </#if> </ul> Note that FreeMarker doesn't care about the nesting of HTML tags, only about the nesting of FTL tags. It just sees HTML as flat text, it doesn't interpret it in any way. If you try to use a non-existing directive (e.g., you mistype the directive name), FreeMarker will decline to use the template and produce an error message. FreeMarker ignores superfluous white-space inside FTL tags. So you can write this: <#list[BR]   animals       as[BR]      being[BR] >[BR] ${being.name} for ${being.price} Euros[BR] </#list    > You may not, however, insert white-space between the < or </ and the directive name. The complete list and description of all directives can be found in the (but I recommend that you look at the chapter about expressions first). FreeMarker can be configured to use [ and ] instead of < and > in the FTL tags and FTL comments, like [#if user == "Big Joe"]...[/#if]. For more information read: . FreeMarker can be configured so that it understands predefined directives without # (like <if user == "Big Joe">...</if>). However we don't recommend the usage of this mode. For more information read:
Expressions expression When you supply values for interpolations or directive parameters you can use variables or more complex expressions. For example, if x is the number 8 and y is 5, the value of (x + y)/2 resolves to the numerical value 6.5. Before we go into details, let's see some concrete examples: When you supply value for interpolations: The usage of interpolations is ${expression} where expression gives the value you want to insert into the output as text. So ${(5 + 8)/2} prints ``6.5'' to the output (or possibly ``6,5'' if the language of your output is not US English). When you supply a value for the directive parameter: You have already seen the if directive in the Getting Started section. The syntax of this directive is: <#if expression>...</#if>. The expression here must evaluate to a boolean value. For example in <#if 2 < 3> the 2 < 3 (2 is less than 3) is an expression which evaluates to true.
Quick overview (cheat sheet) This is a reminder for those of you who already know FreeMarker or are just experienced programmers: Specify values directly Strings: "Foo" or 'Foo' or "It's \"quoted\"" or r"C:\raw\string" Numbers: 123.45 Booleans: true, false Sequences: ["foo", "bar", 123.45], 1..100 Hashes: {"name":"green mouse", "price":150} Retrieving variables Top-level variables: user Retrieving data from a hash: user.name, user["name"] Retrieving data from a sequence: products[5] Special variable: .main String operations Interpolation (or concatenation): "Hello ${user}!" (or "Free" + "Marker") Getting a character: name[0] Sequence operations Concatenation: users + ["guest"] Sequence slice: products[10..19] or products[5..] Hash operations Concatenation: passwords + {"joe":"secret42"} Arithmetical calculations: (x * 1.5 + 10) / 2 - y % 100 Comparison: x == y, x != y, x < y, x > y, x >= y, x <= y, x &lt; y, ...etc. Logical operations: !registered && (firstVisit || fromEurope) Built-ins: name?upper_case Method call: repeat("What", 3) Missing value handler operators: Default value: name!"unknown" or (user.name)!"unknown" or name! or (user.name)! Missing value test: name?? or (user.name)?? See also: Operator precedence
Specify values directly literal constant Often you want to specify a value directly and not as a result of some calculations.
Strings string literal To specify a string value directly you give the text in quotation marks, e.g.: "some text" or in apostrophe-quote, e.g. 'some text'. The two forms are equivalent. If the text itself contains the character used for the quoting (either " or ') or backslashes, you have to precede them with a backslash; this is called escaping. You can type any other character, including line breaks, in the text directly. Example: ${"It's \"quoted\" and this is a backslash: \\"} ${'It\'s "quoted" and this is a backslash: \\'} will print: It's "quoted" and this is a backslash: \ It's "quoted" and this is a backslash: \ Of course, you could simply type the above text into the template, without using ${...}. But we do it here just for the sake of example, to demonstrate expressions. escape sequences This is the list of all supported escape sequences. All other usage of backlash in string literals is an error and any attempt to use the template will fail. Escape sequence Meaning \" Quotation mark (u0022) \' Apostrophe (a.k.a. apostrophe-quote) (u0027) \\ Back slash (u005C) \n Line feed (u000A) \r Carriage return (u000D) \t Horizontal tabulation (a.k.a. tab) (u0009) \b Backspace (u0008) \f Form feed (u000C) \l Less-than sign: < \g Greater-than sign: > \a Ampersand: & \xCode Character given with its hexadecimal Unicode code (UCS code) The Code after the \x is 1 to 4 hexadecimal digits. For example this all put a copyright sign into the string: "\xA9 1999-2001", "\x0A9 1999-2001", "\x00A9 1999-2001". When the character directly after the last hexadecimal digit can be interpreted as hexadecimal digit, you must use all 4 digits or else FreeMarker will be confused. Note that the character sequence ${ (and #{) has special meaning. It's used to insert the value of expressions (typically: the value of variables, as in "Hello ${user}!"). This will be explained later. If you want to print ${, you should use raw string literals as explained below. raw string literal A special kind of string literals is the raw string literals. In raw string literals, backslash and ${ have no special meaning, they are considered as plain characters. To indicate that a string literal is a raw string literal, you have to put an r directly before the opening quotation mark or apostrophe-quote. Example: ${r"${foo}"} ${r"C:\foo\bar"} will print: ${foo} C:\foo\bar
Numbers number literal To specify a numerical value directly you type the number without quotation marks. You have to use the dot as your decimal separator and must not use any grouping separator symbols. You can use - or + to indicate the sign (+ is redundant). Scientific notation is not yet supported (so 1E3 is wrong). Also, you cannot omit the 0 before the decimal separator (so .5 is wrong). Examples of valid number literals: 0.08, -5.013, 8, 008, 11, +11 Note that numerical literals like 08, +8, 8.00 and 8 are totally equivalent as they all symbolize the number eight. Thus, ${08}, ${+8}, ${8.00} and ${8} will all print exactly same.
Booleans boolean literal literal boolean To specify a boolean value you write true or false. Don't use quotation marks.
Sequences sequence literal numerical sequence numerical range expression range expression To specify a literal sequence, you list the subvariables separated by commas, and put the whole list into square brackets. For example: <#list ["winter", "spring", "summer", "autumn"] as x> ${x} </#list> will print: winter spring summer autumn The items in the list are expressions, so you can do this for example: [2 + 2, [1, 2, 3, 4], "whatnot"]. Here the first subvariable will be the number 4, the second will be another sequence, and the third subvariable will be the string "whatnot". You can define sequences that store a numerical range with start..end, where start and end are expressions that resolve to numerical values. For example 2..5 is the same as [2, 3, 4, 5], but the former is much more efficient (occupies less memory and faster). Note that the square brackets are missing. You can define decreasing numerical ranges too, e.g.: 5..2. (Furthermore, you can omit the end, for example 5.., in which case the sequence will contain 5, 6, 7, 8, ...etc up to the infinity.)
Hashes hash literal literal hash To specify a hash in a template, you list the key/value pairs separated by commas, and put the list into curly brackets. The key and value within a key/value pair are separated with a colon. Here is an example: {"name":"green mouse", "price":150}. Note that both the names and the values are expressions. However, the lookup names must be strings.
Retrieving variables
Top-level variables subvariable accessing To access a top-level variable, you simply use the variable name. For example, the expression user will evaluate to the value of variable stored with name ``user'' in the root. So this will print what you store there: ${user} If there is no such top-level variable, then an error will result when FreeMarker tries to evaluate the expression, and it aborts template processing (unless programmers has configured FreeMarker differently). In this expression the variable name can contain only letters (including non-Latin letters), digits (including non-Latin digits), underline (_), dollar ($), at sign (@) and hash (#). Furthermore, the name must not start with digit.
Retrieving data from a hash subvariable accessing hash accessing subvariable If we already have a hash as a result of an expression, then we can get its subvariable with a dot and the name of the subvariable. Assume that we have this data-model: (root) | +- book | | | +- title = "Breeding green mouses" | | | +- author | | | +- name = "Julia Smith" | | | +- info = "Biologist, 1923-1985, Canada" | +- test = "title" Now we can read the title with book.title, since the book expression will return a hash (as explained in the last chapter). Applying this logic further, we can read the name of the author with this expression: book.author.name. There is an alternative syntax if we want to specify the subvariable name with an expression: book["title"]. In the square brackets you can give any expression as long as it evaluates to a string. So with this data-model you can also read the title with book[test]. More examples; these are all equivalent: book.author.name, book["author"].name, book.author.["name"], book["author"]["name"]. When you use the dot syntax, the same restrictions apply regarding the variable name as with top-level variables (name can contain only letters, digits, _, $, @, etc.). There are no such restrictions when you use the square bracket syntax, since the name is the result of an arbitrary expression. (Note, that to help the FreeMarker XML support, if the subvariable name is * (asterisk) or **, then you do not have to use square bracket syntax.) As with the top-level variables, trying to access a non-existent subvariable causes an error and aborts the processing of the template (unless programmers has configured FreeMarker differently).
Retrieving data from a sequence subvariable accessing sequence accessing subvariable This is the same as for hashes, but you can use the square bracket syntax only, and the expression in the brackets must evaluate to a number, not a string. For example to get the name of the first animal of the example data-model (remember that the number of the first item is 0, not 1): animals[0].name
Special variables special variables Special variables are variables defined by the FreeMarker engine itself. To access them, you use the .variable_name syntax. Normally you don't need to use special variables. They are for expert users. The complete list of special variables can be found in the reference.
String operations string operations
Interpolation (or concatenation) interpolation concatenate strings joining strings string concatenate string interpolation adding strings If you want to insert the value of an expression into a string, you can use ${...} (and #{...}) in string literals. ${...} behaves similarly as in text sections. For example (assume that user is ``Big Joe''): ${"Hello ${user}!"} ${"${user}${user}${user}${user}"} will print: Hello Big Joe! Big JoeBig JoeBig JoeBig Joe Alternatively, you can use the + operator to achieve similar result. This is the old method, and it is called string concatenation. Example: ${"Hello " + user + "!"} ${user + user + user + user} This will print the same as the example with the ${...}-s. A frequent mistake of users is the usage of interpolations in places where it shouldn't/can't be used. Interpolations work only in text sections (e.g. <h1>Hello ${name}!</h1>) and in string literals (e.g. <#include "/footer/${company}.html">). A typical bad usage is <#if ${isBig}>Wow!</#if>, which is syntactically WRONG. You should simply write <#if isBig>Wow!</#if>. Also, <#if "${isBig}">Wow!</#if> is WRONG too, since the parameter value will be a string, and the if directive wants a boolean value, so it will cause a runtime error.
Getting a character charAt get character You can get a single character of a string at a given index similarly as you can read the subvariable of a sequence, e.g. user[0]. The result will be a string whose length is 1; FTL doesn't have a separate character type. As with sequence subvariables, the index must be a number that is at least 0 and less than the length of the string, or else an error will abort the template processing. Since the sequence subvariable syntax and the character getter syntax clashes, you can use the character getter syntax only if the variable is not a sequence as well (which is possible because FTL supports multi-typed values), since in that case the sequence behavior prevails. (To work this around, you can use the string built-in, e.g. user?string[0]. Don't worry if you don't understand this yet; built-ins will be discussed later.) Example (assume that user is ``Big Joe''): ${user[0]} ${user[4]} will print (note that the index of the first character is 0): B J You can get a range of characters in the same way as you get a sequence slice, e.g ${user[1..4]} and ${user[4..]}. However, it's now depreacted to utilize this, and instead you should use the substring built-in; built-ins will be discussed later.
Sequence operations sequence operations
Concatenation concatenate sequences joining sequences sequence concatenate adding sequences You can concatenate sequences in the same way as strings, with +. Example: <#list ["Joe", "Fred"] + ["Julia", "Kate"] as user> - ${user} </#list> will print: - Joe - Fred - Julia - Kate Note that sequence concatenation is not to be used for many repeated concatenations, like for appending items to a sequence inside a loop. It's just for things like <#list users + admins as person>. Although concatenating sequences is fast and its speed is independently of the size of the concatenated sequences, the resulting sequence will be always a little bit slower to read than the original two sequences were. This way the result of many repeated concatenations is a sequence that is slow to read.
Sequence slice sequence slice sequence slice subsequence With [firstindex..lastindex] you can get a slice of a sequence, where firstindex and lastindex are expressions evaluate to number. For example, if seq stores the sequence "a", "b", "c", "d", "e", "f" then the expression seq[1..4] will evaluate to a sequence that contains "b", "c", "d", "e" (since the item at index 1 is "b", and the item at index 4 is "e"). The lastindex can be omitted, in which case it defaults to the index of the last item of the sequence. For example, if seq stores the sequence "a", "b", "c", "d", "e", "f" again, then seq[3..] will evaluate to a sequence that contains "d", "e", "f". lastindex can be omitted only since FreeMarker 2.3.3. An attempt to access a subvariable past the last subvariable or before the first subvariable of the sequence will cause an error and abort the processing of the template.
Hash operations hash operations
Concatenation concatenate hashes joining hashes hash concatenate adding hashes You can concatenate hashes in the same way as strings, with +. If both hashes contain the same key, the hash on the right-hand side of the + takes precedence. Example: <#assign ages = {"Joe":23, "Fred":25} + {"Joe":30, "Julia":18}> - Joe is ${ages.Joe} - Fred is ${ages.Fred} - Julia is ${ages.Julia} will print: - Joe is 30 - Fred is 25 - Julia is 18 Note that hash concatenation is not to be used for many repeated concatenations, like for adding items to a hash inside a loop. It's the same as with the sequence concatenation.
Arithmetical calculations arithmetic math addition subtraction division modulus This is the basic 4-function calculator arithmetic plus the modulus operator. So the operators are: Addition: + Subtraction: - Multiplication: * Division: / Modulus (remainder): % Information about the precision? Example: ${100 - x * x} ${x / 2} ${12 % 10} Assuming that x is 5, it will print: 75 2.5 2 Both operands must be expressions which evaluate to a numerical value. So the example below will cause an error when FreeMarker tries to evaluate it, since "5" is a string and not the number 5: ${3 * "5"} <#-- WRONG! --> There is an exception to the above rule. The + operator, is used to concatenate strings as well. If on one side of + is a string and on the other side of + is a numerical value, then it will convert the numerical value to string (using the format appropriate for language of the page) and then use the + as string concatenation operator. Example: ${3 + "5"} will output this: 35 Generally, FreeMarker never converts a string to a number automatically, but it may convert a number to a string automatically. integer division integer part People often want only the integer part of the result of a division (or of other calculations). This is possible with the int built-in. (Built-ins are explained later): ${(x/2)?int} ${1.1?int} ${1.999?int} ${-1.1?int} ${-1.999?int} Assuming that x is 5, it will print: 2 1 1 -1 -1
Comparison comparison operators Sometimes you want to know if two values are equal or not, or which value is the greater. To show concrete examples I will use the if directive here. The usage of if directive is: <#if expression>...</#if>, where expression must evaluate to a boolean value or else an error will abort the processing of the template. If the value of expression is true then the things between the begin and end-tag will be processed, otherwise they will be skipped. To test two values for equality you use = (or == as in Java or C; the two are absolutely equivalent.) To test two values for inequality you use !=. For example, assume that user is ``Big Joe'': <#if user = "Big Joe"> It is Big Joe </#if> <#if user != "Big Joe"> It is not Big Joe </#if> The user = "Big Joe" expression in the <#if ...> will evaluate to the boolean true, so the above will say ``It is Big Joe''. The expressions on both sides of the = or != must evaluate to a scalar. Furthermore, the two scalars must have the same type (i.e. strings can only be compared to strings and numbers can only be compared to numbers, etc.) or else an error will abort template processing. For example <#if 1 = "1"> will cause an error. Note that FreeMarker does exact comparison, so string comparisons are case and white-space sensitive: "x" and "x " and "X" are not equal values. For numerical and date values you can also use <, <=, >= and >. You can't use them for strings! Example: <#if x <= 12> x is less or equivalent with 12 </#if> There is a little problem with >= and >. FreeMarker interprets the > as the closing character of the FTL tag. To prevent this, you have to put the expression into parentheses: <#if (x > y)>. Or, you can use &gt; and &lt; on the place of the problematic relation marks: <#if x &gt; y>. (Note that in general FTL does not support entity references (those &...; things) in FTL tags; it is just an exception with the arithmetical comparisons.). Also, as an alternative you can use lt instead of <, lte instead of <=, gt instead of > and gte instead of >=. And, for historical reasons FTL also understands \lt, \lte, \gt and \gte which are the same as the ones without the backslash.
Logical operations boolean operations logical operations or and not Just the usual logical operators: Logical or: || Logical and: && Logical not: ! The operators will work with boolean values only. Otherwise an error will abort the template processing. Example: <#if x < 12 && color = "green"> We have less than 12 things, and they are green. </#if> <#if !hot> <#-- here hot must be a boolean --> It's not hot. </#if>
Built-ins built-in Built-ins provide, as the name suggest, certain built-in functionality that is always available. Typically, a built-in provides a different version of a variable, or some information about the variable in question. The syntax for accessing a built-in is like that of accessing a subvariable in a hash, except that you use the question mark instead of a dot. For example, to get the upper case version of a string: user?upper_case. You can find the complete list of built-ins in the Reference. For now, just a few of the more important ones: Built-ins to use with strings: html: The string with all special HTML characters replaced with entity references (E.g. < with &lt;). cap_first: The string with the first letter converted to upper case lower_case: The lowercase version of the string upper_case: The uppercase version of the string trim: The string without leading and trailing white-spaces Built-ins to use with sequences: size: The number of elements in the sequence Built-ins to use with numbers: int: The integer part of a number (e.g. -1.9?int is -1) Example: ${test?html} ${test?upper_case?html} Assuming that test stores the string ``Tom & Jerry'', the output will be: Tom &amp; Jerry TOM &amp; JERRY Note the test?upper_case?html. Since the result of test?upper_case is a string, you can use the html built-in with it. Another example: ${seasons?size} ${seasons[1]?cap_first} <#-- left side can by any expression --> ${"horse"?cap_first} Assuming that seasons stores the sequence "winter", "spring", "summer", "autumn", the output will be: 4 Spring Horse
Method call call a method method call If you have a method then you can use the method call operation on it. The method call operation is a comma-separated list of expressions in parentheses. These values are called parameters. The method call operation passes these values to the method which will in turn return a result. This result will be the value of the whole method call expression. For example, assume the programmers have made available a method variable called repeat. You give a string as the first parameter, and a number as the second parameter, and it returns a string which repeats the first parameter the number of times specified by the second parameter. ${repeat("What", 3)} will print: WhatWhatWhat Here repeat was evaluated to the method variable (according to how you access top-level variables) and then ("What", 3) invoked that method. I would like to emphasize that method calls are just plain expressions, like everything else. So this: ${repeat(repeat("x", 2), 3) + repeat("What", 4)?upper_case} will print this: xxxxxxWHATWHATWHATWHAT
Handling missing values These operators exist since FreeMarker 2.3.7 (replacing the default, exists and if_exists built-ins). undefined variable missing variable null handling null-s error handling As we explained earlier, an error will occur and abort the template processing if you try to access a missing variable. However two special operators can suppress this error, and handle the problematic situation. The handled variable can be top-level variable, hash subvariable, or sequence subvariable as well. Furthermore these operators handle the situation when a method call doesn't return a value (from the viewpoint of Java programmers: it returns null or it's return type is void), so it's more correct to say that these operators handle missing values in general, rather than just missing variables. For those who know what's Java null, FreeMarker 2.3.x treats them as missing values. Simply, the template language doesn't know the concept of null. For example, if you have a bean that has a maidenName property, and the value of that property is null, then that's the same as if there were no such property at all, as far as the template is concerned (assuming you didn't configured FreeMarker to use some extreme object wrapper, that is). The result of a method call that returns null is also treated as a missing variable (again, assuming that you use some usual object wrapper). See more in the FAQ. If you wonder why is FreeMarker so picky about missing variables, read this FAQ entry.
Default value operator default value operator Synopsis: unsafe_expr!default_expr or unsafe_expr! or (unsafe_expr)!default_expr or (unsafe_expr)! This operator allows you to specify a default value for the case when the value is missing. Example. Assume no variable called mouse is present: ${mouse!"No mouse."} <#assign mouse="Jerry"> ${mouse!"No mouse."} The output will be: No mouse. Jerry The default value can be any kind of expression, so it doesn't have to be a string. For example you can write hits!0 or colors!["red", "green", "blue"]. There is no restriction regarding the complexity of the expression that specifies the default value, for example you can write: cargo.weight!(item.weight * itemCount + 10). If you have a composite expression after the !, like 1 + x, always use parenthesses, like ${x!(1 + y)} or ${(x!1) + y)}, depending on which interpretation you meant. That's needed because due to a programming mistake in FreeMarker 2.3.x, the precedence of ! (when it's used as default value operator) is very low at its right side. This means that, for example, ${x!1 + y} is misinterpreted by FreeMarker as ${x!(1 + y)} while it should mean ${(x!1) + y}. This programming error will be fixed in FreeMarker 2.4, so you should not utilize this wrong behavior, or else your templates will break with FreeMarker 2.4! If the default value is omitted, then it will be empty string and empty sequence and empty hash at the same time. (This is possible because FreeMarker allows multi-type values.) Note the consequence that you can't omit the default value if you want it to be 0 or false. Example: (${mouse!}) <#assign mouse = "Jerry"> (${mouse!}) The output will be: () (Jerry) Due to syntactical ambiguities <@something a=x! b=y /> will be interpreted as <@something a=x!(b=y) />, that is, the b=y will be interpreted as a comparison that gives the default value for x, rather than the specification of the b parameter. To prevent this, write: <@something a=(x!) b=y /> You can use this operator in two ways with non-top-level variables: product.color!"red" This will handle if color is missing inside product (and returns "red" if so), but will not handle if product is missing. That is, the product variable itself must exist, otherwise the template processing will die with error. (product.color)!"red" This will handle if product.color is missing. That is, if product is missing, or product exists but it does not contain color, the result will be "red", and no error will occur. The important difference between this and the previous example is that when surrounded with parentheses, it is allowed for any component of the expression to be undefined, while without parentheses only the last component of the expression is allowed to be undefined. Of course, the default value operator can be used with sequence subvariables as well: <#assign seq = ['a', 'b']> ${seq[0]!'-'} ${seq[1]!'-'} ${seq[2]!'-'} ${seq[3]!'-'} the outpur will be: a b - - A negative sequence index (as seq[-1]!'-') will always cause an error, you can't suppress that with this or any other operator.
Missing value test operator existence test operator missing value test operator testing for null testing for missing testing for undefined is null Synopsis: unsafe_expr?? or (unsafe_expr)?? This operator tells if a value is missing or not. Depending on that, the result is either true or false. Example. Assume no variable called mouse is present: <#if mouse??> Mouse found <#else> No mouse found </#if> Creating mouse... <#assign mouse = "Jerry"> <#if mouse??> Mouse found <#else> No mouse found </#if> The output will be: No mouse found Creating mouse... Mouse found With non-top-level variables the rules are the same as with the default value operator, that is, you can write product.color?? and (product.color)??.
Parentheses parentheses Parentheses can be used to group any expressions. Some examples: <#-- Output will be: --> ${3 * 2 + 2} <#-- 8 --> ${3 * (2 + 2)} <#-- 12 --> ${3 * ((2 + 2) * (1 / 2))} <#-- 6 --> ${"green " + "mouse"?upper_case} <#-- green MOUSE --> ${("green " + "mouse")?upper_case} <#-- GREEN MOUSE --> <#if !( color = "red" || color = "green")> The color is nor red nor green </#if> Note that the parentheses of a method call expressions have nothing to do with the parentheses used for grouping.
White-space in expressions FTL ignores superfluous white-space in expressions. So these are totally equivalent: ${x + ":" + book.title?upper_case} and ${x+":"+book.title?upper_case} and ${ x + ":" + book . title ? upper_case }
Operator precedence precedence operator precedence The following table shows the precedence assigned to the operators. The operators in this table are listed in precedence order: the higher in the table an operator appears, the higher its precedence. Operators with higher precedence are evaluated before operators with a relatively lower precedence. Operators on the same line have equal precedence. When binary operators (operators with two ``parameters'', as + and -) of equal precedence appear next to each other, they are evaluated in left-to-right order. Operator group Operators highest precedence operators [subvarName] [subStringRange] . ? (methodParams) expr! expr?? unary prefix operators +expr -expr !expr multiplicative * / % additive + - relational < > <= >= (and quivalents: gt, lt, etc.) equality == != (and equivalents: =) logical AND && logical OR || numerical range .. For those of you who master C, Java language or JavaScript, note that the precedence rules are the same as in those languages, except that FTL has some operators that do not exist in those languages. The default value operator (exp!exp) is not yet in the table because of a programming mistake, which will be only fixed in FreeMarker 2.4 due to backward compatibility constraints. It meant to be a "highest precedence operator", but in FreeMarker 2.3.x the precedence on its right side is very low by accident. So if you have a composite expression on the right side, always use paranthesses, etiher like x!(y + 1) or like (x!y) + 1. Never write just x!y + 1.
Interpolations interpolation ${...} The format of interpolations is ${expression}, where expression can be all kind of expression (e.g. ${100 + x}). The interpolation is used to insert the value of the expression converted to text (to string). Interpolations can be used only on two places: in text sections (e.g., <h1>Hello ${name}!</h1>) and in string literal expressions (e.g., <#include "/footer/${company}.html">). A frequent mistake is the usage of interpolations in places where it shouldn't/can't be used. A typical bad usage is <#if ${isBig}>Wow!</#if>, which is syntactically WRONG. You should simply write <#if isBig>Wow!</#if>. Also, <#if "${isBig}">Wow!</#if> is WRONG, since the parameter value will be a string, and the if directive wants a boolean value, so it will cause a runtime error. The result of the expression must be a string, number or date value. This is because only numbers and dates will be converted to string by the interpolation automatically, other types of values (such as booleans, sequences) must be converted to string "manually" somehow (see some advices later), or an error will stop the template processing. Guide for inserting strings; don't forget escaping! If the interpolation is in a text section (i.e., not in a string literal expression), the string that it will insert will be automatically escaped if an escape directive is in effect. If you are generating HTML it's strongly recommended to utilize this to prevent cross-site-scripting attacks and not-well-formed HTML pages. Here's a quick example: <#escape x as x?html> ... <p>Title: ${book.title}</p> <p>Description: <#noescape>${book.description}</#noescape></p> <h2>Comments:</h2> <#list comments as comment> <div class="comment"> ${comment} </div> </#list> ... </#escape> This example shows that when generating HTML you better put the whole template inside the escape directive. Thus, if the book.title contains &, it will be replaced with &amp; in the output so the page remains well-formed HTML. If a user comment contains tags like <iframe> (or any other element), they will become to &lt;iframe&gt; and like, rendering them harmless. But sometimes you really have HTML in the data-model, like let's assume book.description above is stored as HTML in the database, in which case you have to neutralize the enclosing escape with a noescape. Without the enclosing escape, the template would look like: ... <p>Title: ${book.title?html}</p> <p>Description: ${book.description}</p> <h2>Comments:</h2> <#list comments as comment> <div class="comment"> ${comment?html} </div> </#list> ... This does the same as the earlier example, but here you may forget some ?html-s, which is a security risk. In the earlier example you may forget some noescape-s, which gives bad output too, but it's at least no a security risk. Guide for inserting numerical values If the expression evaluates to a number then the numerical value will be converted to string according the default number format. This may includes the maximum number of decimals, grouping, and like. Usually the programmer should set the default number format; the template author don't have to deal with it (but he can with the number_format setting; see in the documentation of setting directive). You can override the default number format for a single interpolation with the string built-in. The decimal separator used (and other such symbols, like the group separator) depends on the current locale (language, country), that also should be set by the programmer. For example, this template: ${1.5} will print something like this if the current locale is English: 1.5 but if the current locale is Hungarian then it will print something like: 1,5 since Hungarian people use comma as decimal separator. You can modify the formatting for a single interpolation with the string built-in. As you can see, interpolations print for human audience (by default at least), as opposed to ''computer audience''. In some cases this is not good, like when you print a database record ID-s as the part of an URL or as an invisible field value in a HTML form, or when you print CSS/JavaScript numerical literals, because these printed values will be read by computer programs and not by humans. Most computer programs are very particular about the format of the numbers, and understand only a kind of simple US number formatting. For that, use the c (stands for ''computer audience'') built-in, for example: <a href="/shop/productdetails?id=${product.id?c}">Details...</a> Guide for inserting date/time values If the expression evaluates to a date then the numerical value will be transformed to a text according to a default format. Usually the programmer should set the default format; you don't have to deal with it (but if you care, see the date_format, time_format and datetime_format settings in the documentation of the setting directive). You can override the default formatting for a single interpolation with the string built-in. To display a date as text, FreeMarker must know which parts of the date are in use, that is, if only the date part (year, month, day), or only the time part (hour, minute, second, millisecond), or both. Unfortunately, because of the technical limitations of Java platform, for some variables it is not possible to detect this automatically; ask the programmer if the data-model contains such problematic variables. If it is not possible to find out which parts of the date are in use, then you must help FreeMarker with the date, time and datetime built-ins, or it will stop with error. Guide for inserting boolean values An attempt to print boolean values with interpolation causes an error and aborts template processing. For example this will cause an error: ${a == 2} and will not print ''true'' or something like that. However, you can convert booleans to strings with the ?string built-in. For example, to print the value of the "married" variable (assuming it's a boolean), you could write ${married?string("yes", "no")}. The exact conversion rules For those who are interested, the exact rules of conversion from the expression value to string (which is then still subject to escaping) are these, in this order: If the value is a number, then it is converted to string in the format specified with the number_format setting. So this usually formats for human audience, as opposed to computer audience. Else if the value is whatever kind of date, time or date-time, then it is converted to string in the format specified with the time_format, date_format, or datetime_format setting, depending on whether the date information is time-only, date-only, or a date-time. If it can't be detected what kind of date it is (date vs time vs date-time), an error will occur. Else if the value is a string, then there is no conversion. Else if the engine is in classic compatibility mode: If the value is a boolean, true values are converted to "true", false values are converted to an empty string. If the expression is undefined (null or a variable is undefined), it is converted to an empty string. Else an error will abort the template processing. Else an error will abort the template processing.
Miscellaneous Do we need a short chapter on i18n/charset issues in general, with the introduction of FreeMarker facilities on this field at the end?
Defining your own directives macro transform custom directive user-defined directive directive user-defined tag user-defined As far as template authors are concerned, user-defined directives can be defined using the macro directive. Java programmers who want to implement directives in Java Language, rather than in a template, should use freemarker.template.TemplateDirectiveModel (see more here...).
Basics defining macro A macro is a template fragment associated with a variable. You can use that variable in your template as a user-defined directive, so it helps in repetitive tasks. For example, this creates a macro variable that prints a big ``Hello Joe!'': <#macro greet> <font size="+2">Hello Joe!</font> </#macro> The macro directive itself does not print anything; it just creates the macro variable, so there will be a variable called greet. Things between the <#macro greet> and </#macro> (called macro definition body) will be executed only when you use the variable as directive. You use user-defined directives by writing @ instead of # in the FTL tag. Use the variable name as the directive name. Also, the end-tag for user-defined directives is mandatory. So you use greet like this: <@greet></@greet> But since <anything></anything> is equivalent with <anything/> you should use this shorter form (that is familiar for you if you know XML): <@greet/> This will print: <font size="+2">Hello Joe!</font> But macros can do much more, since the thing between <#macro ...> and </#macro> is a template fragment, thus it can contain interpolations (${...}) and FTL tags (e.g. <#if ...>...</#if>). Programmers will say on <@...> that you call the macro.
Parameters Let's improve the greet macro so it can use arbitrary name, not only ``Joe''. For this purpose you can use parameters. You define the parameters after the name of the macro in the macro directive. Here we define one parameter for the greet macro, person: <#macro greet person> <font size="+2">Hello ${person}!</font> </#macro> and then you can use this macro as: <@greet person="Fred"/> and <@greet person="Batman"/> which is similar to HTML syntax. This will print: <font size="+2">Hello Fred!</font> and <font size="+2">Hello Batman!</font> As you can see, the actual value of the macro parameter is accessible in the macro definition body as a variable (person). As with predefined directives, the value of a parameter (the right side of =) is an FTL expression. Thus, unlike with HTML, the quotation marks around "Fred" and "Batman" are not optional. <@greet person=Fred/> would mean that you use the value of variable Fred for the person parameter, rather than the string "Fred". Of course parameter value need not be a string, it can be number, boolean, hash, sequence, ...etc., also you can use complex expression on the left side of = (e.g. someParam=(price + 50)*1.25). User-defined directives can have multiple parameters. For example, add a new parameter color: <#macro greet person color> <font size="+2" color="${color}">Hello ${person}!</font> </#macro> and then you can use this macro like: <@greet person="Fred" color="black"/> The order of parameters is not important, so this is equivalent with the previous: <@greet color="black" person="Fred"/> When you call the macro, you can use only parameters that you have defined in the macro directive (in this case: person and color). So if you try <@greet person="Fred" color="black" background="green"/> then you will get an error, since you haven't mentioned parameter background in the <#macro ...>. Also, you must give value for all parameters that you have defined for the macro. So if you try <@greet person="Fred"/> then you will get an error, since you forgot to specify the value of color. However, it often happens that you would specify the same value for a parameter in most cases, so you want to specify the value only when you want a different value for it than the usual. This can be achieved if you specify the parameter in the macro directive as param_name=usual_value. For example, you want to use "black" for color if you don't specify value for that parameter when you use the greet directive: <#macro greet person color="black"> <font size="+2" color="${color}">Hello ${person}!</font> </#macro> Now <@greet person="Fred"/> is OK, since it is equivalent with <@greet person="Fred" color="black"/>, thus the value of color parameter is known. If you want "red" for color, then you write <@greet person="Fred" color="red"/>, and this value will override the usual value specified with the macro directive, so the value of color parameter will be "red". Also, it is important to realize that -- according to the already explained FTL expression rules -- someParam=foo and someParam="${foo}" are very different. In the fist case, you use the value of variable foo as the value of the parameter. In the second case, you use a string literal with interpolation, so the value of the parameter will be a string -- in this case, the value of foo rendered to text -- regardless of the type (as number, date, etc.) of foo. Or, another example: someParam=3/4 and someParam="${3/4}" are different. If the directive wants a numerical value for someParam, it will not like the second variation. Do not exchange these. A very important aspect of macro parameters is that they are local variables. For more information about local variables please read:
Nested content Custom directive can have nested content, similarly as predefined directives like <#if ...>nested content</#if> can have. For example, this creates a macro that draws borders around its nested content: <#macro border> <table border=4 cellspacing=0 cellpadding=4><tr><td> <#nested> </tr></td></table> </#macro> The <#nested> directive executes the template fragment between the start-tag and end-tags of the directive. So if you do this: <@border>The bordered text</@border> the output will be: <table border=4 cellspacing=0 cellpadding=4><tr><td> The bordered text </td></tr></table> The nested directive can be called for multiple times, for example: <#macro do_thrice> <#nested> <#nested> <#nested> </#macro> <@do_thrice> Anything. </@do_thrice> will print: Anything. Anything. Anything. If you don't use the nested directive, then the nested content will not be executed. Thus, if you accidentally use the greet directive like this: <@greet person="Joe"> Anything. </@greet> then FreeMarker will not see this as an error, and simply prints: <font size="+2">Hello Joe!</font> and the nested content will be ignored, since the greet macro never uses nested directive. The nested content can be anything that is valid FTL, including other user-defined directives. Thus this is OK: <@border> <ul> <@do_thrice> <li><@greet person="Joe"/> </@do_thrice> </ul> </@border> and will print: <table border=4 cellspacing=0 cellpadding=4><tr><td> <ul> <li><font size="+2">Hello Joe!</font> <li><font size="+2">Hello Joe!</font> <li><font size="+2">Hello Joe!</font> </ul> </tr></td></table> The local variables of a macro are not visible in the nested content. Say, this: <#macro repeat count> <#local y = "test"> <#list 1..count as x> ${y} ${count}/${x}: <#nested> </#list> </#macro> <@repeat count=3>${y!"?"} ${x!"?"} ${count!"?"}</@repeat> will print this: test 3/1: ? ? ? test 3/2: ? ? ? test 3/3: ? ? ? because the y, x and count are the local (private) variables of the macro, and are not visible from outside the macro definition. Furthermore, a different set of local variables is used for each macro call, so this will not cause confusion: <#macro test foo>${foo} (<#nested>) ${foo}</#macro> <@test foo="A"><@test foo="B"><@test foo="C"/></@test></@test> and will print this: A (B (C () C) B) A
Macros with loop variables loop variable Predefined directives like list can use so-called loop variables; you should read to understand loop variables. User-defined directives can also have loop variables. For example, let's extend the do_thrice directive of the earlier examples so it exposes the current repetition number as a loop variable. As with the predefined directives (as list) the name of loop variables is given when you call the directive (as foo in <#list foos as foo>...</#list>), while the value of the variables is set by the directive itself. <#macro do_thrice> <#nested 1> <#nested 2> <#nested 3> </#macro> <@do_thrice ; x> <#-- user-defined directive uses ";" instead of "as" --> ${x} Anything. </@do_thrice> This will print: 1 Anything. 2 Anything. 3 Anything. The syntactical rule is that you pass the actual value of the loop variable for a certain "loop" (i.e. repetition of the nested content) as the parameter of nested directive (of course the parameter can by arbitrary expression). The name of the loop variable is specified in the user-defined directive open tag (<@...>) after the parameters and a semicolon. A macro can use more the one loop variable (the order of variables is significant): <#macro repeat count> <#list 1..count as x> <#nested x, x/2, x==count> </#list> </#macro> <@repeat count=4 ; c, halfc, last> ${c}. ${halfc}<#if last> Last!</#if> </@repeat> The output will be: 1. 0.5 2. 1 3. 1.5 4. 2 Last! It is not a problem if you specify different number of loop variables in the user-defined directive start-tag (that is, after the semicolon) than with the nested directive. If you specify less loop variables after the semicolon, then simply you will not see the last few values that the nested directive provides, since there is no loop variable to hold those values. So these are all OK: <@repeat count=4 ; c, halfc, last> ${c}. ${halfc}<#if last> Last!</#if> </@repeat> <@repeat count=4 ; c, halfc> ${c}. ${halfc} </@repeat> <@repeat count=4> Just repeat it... </@repeat> If you specify more variables after the semicolon than with the nested directive, then the last few loop variables will not be created (i.e. will be undefined in the nested content).
More about user-defined directives and macros Now you may read the relevant parts of the FreeMarker Reference: user-defined directive call macro directive You can define methods in FTL as well, see the function directive. Also, you may interested in namespaces: . Namespaces help you to organize and reuse your commonly used macros.
Defining variables in the template variable loop variable local variable temporary variable As we have described, a template can use the variables defined in the data-model. A template can also define variables outside the data-model for its own use. These temporary variables can be created and replaced using FTL directives. Note that each template processing job has its own private set of these variables that exists while the given page is being rendered. This variable set is initially empty, and will be thrown away when the template processing job has been finished. You access a variable that you have defined in the template exactly as if it were a variable in the data-model root. The variable has precedence over any variable of the same name defined in the data-model. That is, if you define a variable called ``foo'' and coincidentally, there is a ``foo'' in the data-model as well, then the variable created in the template will hide (not overwrite!) the variable in the data-model root. For example, ${foo} will print the value of the variable created in the template. There are 3 kind of variables that are defined in a template: ``plain'' variables: They are accessible from everywhere in the template, or from the templates inserted with include directive. You can create and replace these variables with the assign or macro directives. Local variables: They can only be set inside a macro definition body, and are only visible from there. A local variable only exists for the duration of a macro call. You can create and replace local variables inside macro definition bodies with the local directive. Loop variables: Loop variables are created automatically by directives like list, and they only exist between the start-tag and end-tag of the directive. Macro parameters are local variables, not loop variables. Example: Create and replace variables with assign: <#assign x = 1> <#-- create variable x --> ${x} <#assign x = x + 3> <#-- replace variable x --> ${x} Output: 1 4 Local variables hide (not overwrite) ``plain'' variables of the same name. Loop variables hide (not overwrite) local and ``plain'' variables of the same name. For example: <#assign x = "plain"> 1. ${x} <#-- we see the plain var. here --> <@test/> 6. ${x} <#-- the value of plain var. was not changed --> <#list ["loop"] as x> 7. ${x} <#-- now the loop var. hides the plain var. --> <#assign x = "plain2"> <#-- replace the plain var, hiding does not mater here --> 8. ${x} <#-- it still hides the plain var. --> </#list> 9. ${x} <#-- the new value of plain var. --> <#macro test> 2. ${x} <#-- we still see the plain var. here --> <#local x = "local"> 3. ${x} <#-- now the local var. hides it --> <#list ["loop"] as x> 4. ${x} <#-- now the loop var. hides the local var. --> </#list> 5. ${x} <#-- now we see the local var. again --> </#macro> the output: 1. plain 2. plain 3. local 4. loop 5. local 6. plain 7. loop 8. loop 9. plain2 An inner loop variable can hide an outer loop variable: <#list ["loop 1"] as x> ${x} <#list ["loop 2"] as x> ${x} <#list ["loop 3"] as x> ${x} </#list> ${x} </#list> ${x} </#list> the output: loop 1 loop 2 loop 3 loop 2 loop 1 Note that the value of a loop variable is set by the directive invocation that has created it (the <list ...> tags in this case). There is no other way to change the value of a loop variable (say, you can't change its value with some kind of assignment directive). You can hide temporarily a loop variable with another loop variable though, as you have seen above. Sometimes it happens that a variable hides the variable in the data-model with the same name, but you want to read the variable of the data-model. In this case you can use the special variable globals. For example, assume we have a variable called user in the data-model with value ``Big Joe'': <#assign user = "Joe Hider"> ${user} <#-- prints: Joe Hider --> ${.globals.user} <#-- prints: Big Joe --> For information about syntax of variables please read:
Namespaces namespaces libraries When you run FTL templates, you have a (possibly empty) set of variables that you have created with assign and macro directives, as can be seen from the previous chapter. A set of variables like this is called a namespace. In simple cases you use only one namespace, the so-called main namespace. You don't realize this, since normally you use only this namespace. But if you want to build reusable collection of macros, functions and other variables -- usually referred as library by lingo -- the usage of multiple namespaces becomes inevitable. Just consider if you have a big collection of macros, that you use in several projects, or even you want to share it with other people. It becomes impossible to be sure that the library does not have a macro (or other variable) with the same name as the name of a variable in the data-model, or with the same name as a the name of a variable in another library used in the template. In general, variables can clobber each other because of the name clashes. So you should use a separate namespace for the variables of each library.
Creating a library Let's create a simple library. Assume you commonly need the variables copyright and mail (before you ask, macros are variables): <#macro copyright date> <p>Copyright (C) ${date} Julia Smith. All rights reserved.</p> </#macro> <#assign mail = "jsmith@acme.com"> Store the above in the file lib/my_test.ftl (in the directory where you store the templates). Assume you want to use this in aWebPage.ftl. If you use <#include "/lib/my_test.ftl"> in the aWebPage.ftl, then it will create the two variables in the main namespace, and it is not good now, since you want them to be in a namespace that is used exclusively by the ``My Test Library''. Instead of include you have to use import directive. This directive is, at the first glance, similar to include, but it will create an empty namespace for lib/my_test.ftl and will execute that there. lib/my_test.ftl will find itself in an clean new world, where only the variables of data-model are present (since they are visible from everywhere), and will create the two variables in this new world. That's fine for now, but you want to access the two variables from aWebPage.ftl, and that uses the main namespace, so it can't see the variables of the other namespace. The solution is that the import directive not only creates the new namespace, but a new hash variable in the namespace used by the caller of import (the main namespace in this case), that will act as a gate into the newly created namespace. So this is how aWebPage.ftl will look like: <#import "/lib/my_test.ftl" as my> <#-- the hash called "my" will be the "gate" --> <@my.copyright date="1999-2002"/> ${my.mail} Note how it accesses the variables in the namespace created for /lib/my_test.ftl using the newly created namespace accessing hash, my. This will print: <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved.</p> jsmith@acme.com If you would have a variable called mail or copyright in the main namespace, that would not cause any confusion, since the two templates use separated namespaces. For example, modify the copyright macro in lib/my_test.ftl to this: <#macro copyright date> <p>Copyright (C) ${date} Julia Smith. All rights reserved. <br>Email: ${mail}</p> </#macro> and then replace aWebPage.ftl with this: <#import "/lib/my_test.ftl" as my> <#assign mail="fred@acme.com"> <@my.copyright date="1999-2002"/> ${my.mail} ${mail} and the output will be this: <p>Copyright (C) 1999-2002 Julia Smith. All rights reserved. <br>Email: jsmith@acme.com</p> jsmith@acme.com fred@acme.com This is like that because when you have called the copyright macro, FreeMarker has temporarily switch to the namespace that was created by the import directive for /lib/my_test.ftl. Thus, the copyright macro always sees the mail variable that exists there, and not the other mail that exists in the main namespace.
Writing the variables of imported namespaces Occasionally you may want to create or replace a variable in an imported namespace. You can do this with the assign directive, if you use its namespace parameter. For example, this: <#import "/lib/my_test.ftl" as my> ${my.mail} <#assign mail="jsmith@other.com" in my> ${my.mail} will output this: jsmith@acme.com jsmith@other.com
Namespaces and data-model The variables of the data-model are visible from everywhere. For example, if you have a variable called user in the data-model, lib/my_test.ftl will access that, exactly as aWebPage.ftl does: <#macro copyright date> <p>Copyright (C) ${date} ${user}. All rights reserved.</p> </#macro> <#assign mail = "${user}@acme.com"> If user is ``Fred'', then the usual example: <#import "/lib/my_test.ftl" as my> <@my.copyright date="1999-2002"/> ${my.mail} will print this: <p>Copyright (C) 1999-2002 Fred. All rights reserved.</p> Fred@acme.com Don't forget that the variables in the namespace (the variables you create with assign or macro directives) have precedence over the variables of the data-model when you are in that namespace. Thus, the contents of data-model does not interfere with the variables created by the library. In some unusual applications you want to create variables in the template those are visible from all namespaces, exactly like the variables of the data-model. But you can't change the data-model with templates. Still, it is possible to achieve similar result with the global directive; read the reference for more details.
The life-cycle of namespaces A namespace is identified by the path that was used with the import directive. If you try to import with the same path for multiple times, it will create the namespace and run the template specified by the path for the very first invocation of import only. The later imports with the same path will just create a ``gate'' hash to the same namespace. For example, let this be the aWebPage.ftl: <#import "/lib/my_test.ftl" as my> <#import "/lib/my_test.ftl" as foo> <#import "/lib/my_test.ftl" as bar> ${my.mail}, ${foo.mail}, ${bar.mail} <#assign mail="jsmith@other.com" in my> ${my.mail}, ${foo.mail}, ${bar.mail} The output will be: jsmith@acme.com, jsmith@acme.com, jsmith@acme.com jsmith@other.com, jsmith@other.com, jsmith@other.com since you see the same namespace through my, foo and bar. Note that namespaces are not hierarchical, they exist independently of each other. That is, if you import namespace N2 while you are in name space N1, N2 will not be inside N1. N1 just gets a hash by which it can access N2. This is the same N2 namespace that you would access if, say, you import N2 when you are in the main namespace. Each template processing job has its own private set of namespaces. Each template-processing job is a separated cosmos that exists only for the short period of time while the given page is being rendered, and then it vanishes with all its populated namespaces. Thus, whenever we say that ``import is called for the first time'' and such, we are always talking in the context of a single template processing job.
Writing libraries for other people library path If you have written a good quality library that can be useful for other people, you may want to make it available on the Internet (like on http://freemarker.org/libraries.html). To prevent clashes with the names of libraries used by other authors, and to make it easy to write libraries that import other published libraries, there is a de-facto standard that specifies the format of library paths. The standard is that the library must be available (importable) for templates and other libraries with a path like this: /lib/yourcompany.com/your_library.ftl For example if you work for Example Inc. that owns the www.example.com homepage, and you develop a widget library, then the path of the FTL file to import should be: /lib/example.com/widget.ftl Note that the www is omitted. The part after the 3rd slash can contain subdirectories such as: /lib/example.com/commons/string.ftl An important rule is that the path should not contain upper-case letters. To separate words, use _, as in wml_form (not wmlForm). Note that if you do not develop the library for a company or organization, you should use the URL of the project homepage, such as /lib/example.sourceforge.net/example.ftl, or /lib/geocities.com/jsmith/example.ftl.
White-space handling white-space removal The control of the white-space in a template is a problem that to some extent haunts every template engine in the business. Let see this template. I have marked the components of template with colors: text, interpolation, FTL tag. With the [BR]-s I visualize the line breaks. <p>List of users:[BR] <#assign users = [{"name":"Joe", "hidden":false},[BR] {"name":"James Bond", "hidden":true},[BR] {"name":"Julia", "hidden":false}]>[BR] <ul>[BR] <#list users as user>[BR] <#if !user.hidden>[BR] <li>${user.name}[BR] </#if>[BR] </#list>[BR] </ul>[BR] <p>That's all. If FreeMarker were to output all text as is, the output would be: <p>List of users:[BR] [BR] <ul>[BR] [BR] [BR] <li>Joe[BR] [BR] [BR] [BR] [BR] [BR] <li>Julia[BR] [BR] [BR] </ul>[BR] <p>That's all. You have a lot of unwanted spaces and line breaks here. Fortunately neither HTML nor XML is typically white-space sensitive, but this amount of superfluous white-space can be annoying, and needlessly increases the size of produced HTML. Of course, it is even bigger problem when outputting white-space-sensitive formats. FreeMarker provides the following tools to cope with this problem: Tools to ignore certain white-space of the template files (parse time white-space removal): White-space stripping: This feature automatically ignores typical superfluous white-space around FTL tags. It can be enabled or disabled on per template manner. Trimmer directives: t, rt, lt. With these directives you can explicitly tell FreeMarker to ignore certain white-space. Read the reference for more information. ftl parameter strip_text: This removes all top-level text from the template. It is useful for templates that contain macro definitions only (and some other non-outputting directives), because it removes the line-breaks that you use between the macro definitions and between the other top-level directives to improve the readability of the template. Tools that remove white-space from the output (on-the-fly white-space removal): compress directive.
White-space stripping white-space removal stripping If this feature is enabled for a template, then it automatically ignores (i.e. does not print to the output) two kind of typical superfluous white-space: Indentation white-space, and trailing white-space at the end of the line (includes the line break) will be ignored in lines that contains only FTL tags (e.g. <@myMacro/>, <#if ...>) and/or FTL comments (e.g. <#-- blah -->), apart from the the ignored white-space itself. For example, if a line contains only an <#if ...>, then the indentation before the tag and the line break after the tag will be ignored. However, if the line contains <#if ...>x, then the white-space in that line will not be ignored, because of the x, as that is not FTL tag. Note that according these rules, a line that contains <#if ...><#list ...> is subject to white-space ignoring, while a line that contains <#if ...> <#list ...> is not, because the white-space between the two FTL tags is embedded white-space, not indentation or trailing white-space. White-space sandwiched between the following directives is ignored: macro, function, assign, global, local, ftl, import, but only if there is only white-space and/or FTL comments between the directives. In practice it means that you can put empty lines between macro definitions and assignments as spacing for better readability, without printing needless empty lines (line breaks) to the output. The output of the last example with white-space stripping enabled will be: <p>List of users:[BR] <ul>[BR] <li>Joe[BR] <li>Julia[BR] </ul>[BR] <p>That's all. This is because after stripping the template becomes the following; the ignored text is not colored: <p>List of users:[BR] <#assign users = [{"name":"Joe", "hidden":false},[BR] {"name":"James Bond", "hidden":true},[BR] {"name":"Julia", "hidden":false}]>[BR] <ul>[BR] <#list users as user>[BR] <#if !user.hidden>[BR] <li>${user.name}[BR] </#if>[BR] </#list>[BR] </ul>[BR] <p>That's all. White-space stripping can be enabled/disabled in per template manner with the ftl directive. If you don't specify this with the ftl directive, then white-space stripping will be enabled or disabled depending on how the programmer has configured FreeMarker. The factory default is white-space stripping enabled, and the programmers probably left it so (recommended). Note that enabling white-space stripping does not degrade the performance of template execution; white-space stripping is done during template loading. White-space stripping can be disabled for a single line with the nt directive (for No Trim).
Using compress directive white-space removal compress Another solution is to use the compress directive. As opposed to white-space stripping, this works directly on the generated output, not on the template. That is, it will investigate the printed output on the fly, and does not investigate the FTL program that creates the output. It aggressively removes indentations, empty lines and repeated spaces/tabs (for more information read the reference). So the output of: <#compress> <#assign users = [{"name":"Joe", "hidden":false}, {"name":"James Bond", "hidden":true}, {"name":"Julia", "hidden":false}]> List of users: <#list users as user> <#if !user.hidden> - ${user.name} </#if> </#list> That's all. </#compress> will be: List of users: - Joe - Julia That's all. Note that compress is totally independent of white-space stripping. So it is possible that the white-space of template is stripped, and later the produced output is compress-ed. Also, by default a user-defined directve called compress is available in the data-model (due to backward compatibility). This is the same as the directive, except that you may optionally set the single_line parameter, which will remove all intervening line breaks. If you replace <#compress>...</#compress> on the last example with <@compress single_line=true>...</@compress>, then you get this output: List of users: - Joe - Julia That's all.
Alternative (square bracket) syntax alternative syntax square bracket syntax This feature exists since FreeMarker 2.3.4. FreeMarker supports an alternative syntax, where [ and ] is used instead of < and > in FreeMarker directives and comments, for example: Calling predefined directive: [#list animals as being]...[/#list] Calling user-defined directive: [@myMacro /] Comment: [#-- the comment --] To use the alternative syntax instead of the default one, start the template with the ftl directive using the alternative syntax. If you don't know what is the ftl directive, just start the template with [#ftl], and remember that it should be the very first thing in the file (except that white-space can precede it). For example, this is how the last example of the Getting Started looks with the alternative syntax (assuming it's a complete template, not just a fragment): [#ftl] <p>We have these animals: <table border=1> <tr><th>Name<th>Price [#list animals as being] <tr> <td> [#if being.size = "large"]<b>[/#if] ${being.name} [#if being.size = "large"]</b>[/#if] <td>${being.price} Euros [/#list] </table> The alternative (square bracket) and the default (angle bracket) syntax are mutually exclusive within a template. That is, either the whole template uses alternative syntax, or the whole template uses the default syntax. If the template uses alternative syntax, things like <#if ...> are count as static text, not as FTL tags. Similarly, if the template uses the default syntax, things like [#if ...] count as static text, not as FTL tags. If you start the file with [#ftl ...] (where the ... stands for the optional parameters; of course [#ftl] works too) the file will surely use the alternative (square bracket) syntax. If you start the file with <#ftl ...> the file will surely use the normal (angle bracket) syntax. If there is no ftl directive in the file, then the programmer decides what the syntax will be by configuring FreeMarker (programmers see Configuration.setTagSyntax(int) in the API javadocs). Most probably the programmers use the factory default however. The factory default in 2.3.x is using the normal syntax. The factory default in 2.4.x will be auto-detection, which means that the first FreeMarker tag determines the syntax (it can be anything, not just ftl).
Programmer's Guide Getting Started Note that, if you are new to FreeMarker, you should read at least the before this chapter.
Create a configuration instance configuration First you have to create a freemarker.template.Configuration instance and adjust its settings. A Configuration instance is a central place to store the application level settings of FreeMarker. Also, it deals with the creation and caching of pre-parsed templates. Probably you will do it only once at the beginning of the application (possibly servlet) life-cycle: Configuration cfg = new Configuration(); // Specify the data source where the template files come from. // Here I set a file directory for it: cfg.setDirectoryForTemplateLoading( new File("/where/you/store/templates")); // Specify how templates will see the data-model. This is an advanced topic... // but just use this: cfg.setObjectWrapper(new DefaultObjectWrapper()); From now you should use this single configuration instance. Note however that if a system has multiple independent components that use FreeMarker, then of course they will use their own private Configuration instance.
Create a data-model data-model assembling with Java In simple cases you can build data-models using java.lang and java.util classes and custom Java Beans: Use java.lang.String for strings. Use java.lang.Number descents for numbers. Use java.lang.Boolean for boolean values. Use java.util.List or Java arrays for sequences. Use java.util.Map for hashes. Use your custom bean class for hashes where the items correspond to the bean properties. For example the price property of product can be get as product.price. (The actions of the beans can be exposed as well; see much later here) For example, let's build the data-model of the first example of the Template Author's Guide. For convenience, here it is again: (root) | +- user = "Big Joe" | +- latestProduct | +- url = "products/greenmouse.html" | +- name = "green mouse" This is the Java code fragment that builds this data-model: // Create the root hash Map root = new HashMap(); // Put string ``user'' into the root root.put("user", "Big Joe"); // Create the hash for ``latestProduct'' Map latest = new HashMap(); // and put it into the root root.put("latestProduct", latest); // put ``url'' and ``name'' into latest latest.put("url", "products/greenmouse.html"); latest.put("name", "green mouse"); For the latestProduct you migh as well use a Java Bean that has url and name properties (that is, an object that has public String getURL() and String getName() methods); it's the same from viewpoint of the template.
Get the template template Java side Templates are represented by freemarker.template.Template instances. Typically you obtain a Template instance from the Configuration instance. Whenever you need a template instance you can get it with its getTemplate method. Store the example template in the test.ftl file of the earlier set directory, then you can do this: Template temp = cfg.getTemplate("test.ftl"); When you call this, it will create a Template instance corresponds to test.ftl, by reading /where/you/store/templates/test.ftl and parsing (compile) it. The Template instance stores the template in the parsed form, and not as text. Configuration caches Template instances, so when you get test.ftl again, it probably will not create new Template instance (thus doesn't read and parse the file), just returns the same instance as for the first time.
Merging the template with the data-model output generate with Java merging As we know, data-model + template = output, and we have a data-model (root) and a template (temp), so to get the output we have to merge them. This is done by the process method of the template. It takes the data-model root and a Writer as parameters. It writes the produced output to the Writer. For the sake of simplicity here I write to the standard output: Writer out = new OutputStreamWriter(System.out); temp.process(root, out); out.flush(); This will print to your terminal the output what you have seen in the first example of the Template Author's Guide. Once you have obtained a Template instance, you can merge it with different data-models for unlimited times (Template instances are basically stateless). Also, the test.ftl file is accessed only while the Template instance is created, not when you call the process method.
Putting all together This is a working source file assembled from the previous fragments. Don't forget to put freemarker.jar into the CLASSPATH. import freemarker.template.*; import java.util.*; import java.io.*; public class Test { public static void main(String[] args) throws Exception { /* ------------------------------------------------------------------- */ /* You should do this ONLY ONCE in the whole application life-cycle: */ /* Create and adjust the configuration */ Configuration cfg = new Configuration(); cfg.setDirectoryForTemplateLoading( new File("/where/you/store/templates")); cfg.setObjectWrapper(new DefaultObjectWrapper()); /* ------------------------------------------------------------------- */ /* You usually do these for many times in the application life-cycle: */ /* Get or create a template */ Template temp = cfg.getTemplate("test.ftl"); /* Create a data-model */ Map root = new HashMap(); root.put("user", "Big Joe"); Map latest = new HashMap(); root.put("latestProduct", latest); latest.put("url", "products/greenmouse.html"); latest.put("name", "green mouse"); /* Merge data-model with template */ Writer out = new OutputStreamWriter(System.out); temp.process(root, out); out.flush(); } } I have suppressed the exceptions for the sake of simplicity. Don't do it in real products.
The Data Model This is just an introductory explanation. See the FreeMarker Java API documentation for more detailed information.
Basics object wrapper wrapper data-model assembling with Java, without object wrapper You have seen how to build a data-model in the Getting Started using the standard Java classes (Map, String, etc.). Internally, the variables available in the template are java objects that implement the freemarker.template.TemplateModel interface. But you could use standard java collections as variables in your data-model, because these were replaced with the appropriate TemplateModel instances behind the scenes. This facility is called object wrapping. The object wrapping facility can convert any kind of object transparently to the instances of classes that implement TemplateModel interface. This makes it possible, for example, to access java.sql.ResultSet as sequence variable in templates, or to access javax.servlet.ServletRequest objects as a hash variable that contains the request attributes, or even to traverse XML documents as FTL variables (see here). To wrap (convert) these objects, however, you need to plug the proper, so called, object wrapper implementation (possibly your custom implementation); this will be discussed later. The meat for now is that any object that you want to access from the templates, sooner or later must be converted to an object that implements TemplateModel interface. So first you should familiarize yourself with writing of TemplateModel implementations. There is roughly one freemarker.template.TemplateModel descendant interface corresponding to each basic type of variable (TemplateHashModel for hashes, TemplateSequenceModel sequences, TemplateNumberModel for numbers, etc.). For example, if you want to expose a java.sql.ResultSet as a sequence for the templates, then you have to write a TemplateSequenceModel implementation that can read java.sql.ResultSet-s. We used to say on this, that you wrap the java.sql.ResultSet with your TemplateModel implementation, as basically you just encapsulate the java.sql.ResultSet to provide access to it with the common TemplateSequenceModel interface. Note that a class can implement multiple TemplateModel interfaces; this is why FTL variables can have multiple types (see: ) Note that a trivial implementation of these interfaces is provided with the freemarker.template package. For example, to convert a String to FTL string variable, you can use SimpleScalar, to convert a java.util.Map to FTL hash variable, you can use SimpleHash, etc. An easy way to try your own TemplateModel implementation, is to create an instance of that, and drop it directly into the data-model (as put it into the root hash). The object wrapper will expose it untouched for the template, as it already implements TemplateModel, so no conversion (wrapping) needed. (This trick is also useful in cases when you do not want the object wrapper to try to wrap (convert) a certain object.)
Scalars scalar Java side string Java side number Java side boolean Java side date Java side time Java side There are 4 scalar types: Boolean Number String Date For each scalar type is a TemplateTypeModel interface, where Type is the name of the type. These interfaces define only one method: type getAsType();. This returns the value of the variable with the Java type (boolean, Number, String and Date respectively). For historical reasons the interface for string scalars is called TemplateScalarModel, not TemplateStringModel. A trivial implementation of these interfaces are available in freemarker.template package with SimpleType class name. However, there is no SimpleBooleanModel; to represent the boolean values you can use the TemplateBooleanModel.TRUE and TemplateBooleanModel.FALSE singletons. For historical reasons the class for string scalars is called SimpleScalar, not SimpleString. Scalars are immutable within FTL. When you set the value of a variable in a template, then you replace the TemplateTypeModel instance with another instance, and don't change the value stored in the original instance.
Difficulties with the date type date Java API related difficulties time Java API related difficulties There is a complication around date types, because Java API usually does not differentiate java.util.Date-s that store only the date part (April 4, 2003), only the time part (10:19:18 PM), or both (April 4, 2003 10:19:18 PM). To display a date variable as text correctly, FreeMarker must know what parts of the java.util.Date stores meaningful information, and what parts are unused. Unfortunately, the only place where the Java API cleanly tells this, is with database handling (SQL), because databases typically has separated date, time and timestamp (aka date-time) types, and java.sql has 3 corresponding java.util.Date subclasses for them. TemplateDateModel interface has two methods: java.util.Date getAsDate() and int getDateType(). A typical implementation of this interface, stores a java.util.Date object, plus an integer that tells the "database style type". The value of this integer must be a constant from the TemplateDateModel interface: DATE, TIME, DATETIME and UNKNOWN. What is UNKNOWN? As we told earlier, java.lang and java.util classes are usually converted automatically into TemplateModel implementations, be so called object wrappers. If the object wrapper faces a java.util.Date, that is not an instance of a java.sql date class, it can't decide what the "database style type" is, so it uses UNKNOWN. Later, if the template has to use this variable, and the "database style type" is needed for the operation, it will stop with error. To prevent this, for the problematic variables the template author must help FreeMarker to decide the "database style type", by using the date, time or datetime built-ins. Note that if you use string built-in with format parameter, as foo?string("MM/dd/yyyy"), then FreeMarker don't need to know the "database style type".
Containers containers Java side These are hashes, sequences, and collections.
Hashes hash Java side Hashes are java objects that implement TemplateHashModel interface. TemplateHashModel contains two methods: TemplateModel get(String key), which returns the subvariable of the given name, and boolean isEmpty(), which indicates if the hash has zero subvariable or not. The get method returns null if no subvariable with the given name exists. The TemplateHashModelEx interface extends TemplateHashModel. It adds methods by which values and keys built-ins can enumerate the subvariables of the hash. The commonly used implementation is SimpleHash, which implements TemplateHashModelEx. Internally it uses a java.util.Hash to store the subvariables. SimpleHash has methods by which you can add and remove subvariable. These methods should be used to initialize the variable directly after its creation. Containers are immutable within FTL. That is, you can't add, replace or remove the subvariables they contain.
Sequences sequence Java side Sequences are java objects that implement TemplateSequenceModel. It contains two methods: TemplateModel get(int index) and int size(). The commonly used implementation is SimpleSequence. It uses internally a java.util.List to store its subvariables. SimpleSequence has methods by which you can add subvariables. These methods should be used to populate the sequence directly after its creation.
Collections collection Java side Collections are java objects that implement the TemplateCollectionModel interface. That interface has one method: TemplateModelIterator iterator(). The TemplateModelIterator interface is similar to java.util.Iterator, but it returns TemplateModels instead of Object-s, and it can throw TemplateModelExceptions. The commonly used implementation is SimpleCollection.
Methods method Java side Method variables exposed to a template implement the TemplateMethodModel interface. This contains one method: TemplateModel exec(java.util.List arguments). When you call a method with a method call expression, then the exec method will be called. The arguments parameter will contain the values of the FTL method call arguments. The return value of exec gives the value of the FTL method call expression. The TemplateMethodModelEx interface extends TemplateMethodModel. It does not add any new methods. The fact that the object implements this marker interface indicates to the FTL engine that the arguments should be put to the java.util.List directly as TemplateModel-s. Otherwise they will be put to the list as String-s. For obvious reasons there is no default implementation for these interfaces. Example: This is a method, which returns the index within the second string of the first occurrence of the first string, or -1 if the second string doesn't contains the first. public class IndexOfMethod implements TemplateMethodModel { public TemplateModel exec(List args) throws TemplateModelException { if (args.size() != 2) { throw new TemplateModelException("Wrong arguments"); } return new SimpleNumber( ((String) args.get(1)).indexOf((String) args.get(0))); } } If you put an instance of this, say, into the root: root.put("indexOf", new IndexOfMethod()); then you can call it in the template: <#assign x = "something"> ${indexOf("met", x)} ${indexOf("foo", x)} and then the output will be: 2 -1 If you need to access the runtime FTL environment (read/write variables, get the current locale, etc.), you can get it with Environment.getCurrentEnvironment().
Directives directives Java side Java programmers can implement user-defined directives in Java using the TemplateDirectiveModel interface. See in the API documentation. TemplateDirectiveModel was introduced in FreeMarker 2.3.11, replacing the soon to be depreciated TemplateTransformModel.
Example 1 We will implement a directive which converts all output between its start-tag and end-tag to upper case. Like, this template: foo <@upper> bar <#-- All kind of FTL is allowed here --> <#list ["red", "green", "blue"] as color> ${color} </#list> baaz </@upper> wombat will output this: foo BAR RED GREEN BLUE BAAZ wombat This is the source code of the directive class: package com.example; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.core.Environment; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; /** * FreeMarker user-defined directive that progressively transforms * the output of its nested content to upper-case. * * * <p><b>Directive info</b></p> * * <p>Directive parameters: None * <p>Loop variables: None * <p>Directive nested content: Yes */ public class UpperDirective implements TemplateDirectiveModel { public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // Check if no parameters were given: if (!params.isEmpty()) { throw new TemplateModelException( "This directive doesn't allow parameters."); } if (loopVars.length != 0) { throw new TemplateModelException( "This directive doesn't allow loop variables."); } // If there is non-empty nested content: if (body != null) { // Executes the nested body. Same as <#nested> in FTL, except // that we use our own writer instead of the current output writer. body.render(new UpperCaseFilterWriter(env.getOut())); } else { throw new RuntimeException("missing body"); } } /** * A {@link Writer} that transforms the character stream to upper case * and forwards it to another {@link Writer}. */ private static class UpperCaseFilterWriter extends Writer { private final Writer out; UpperCaseFilterWriter (Writer out) { this.out = out; } public void write(char[] cbuf, int off, int len) throws IOException { char[] transformedCbuf = new char[len]; for (int i = 0; i < len; i++) { transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]); } out.write(transformedCbuf); } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } } } Now we still need to create an instance of this class, and make this directive available to the template with the name "upper" (or with whatever name we want) somehow. A possible solution is to put the directive in the data-model: root.put("upper", new com.example.UpperDirective()); But typically it is better practice to put commonly used directives into the Configuration as shared variables. It is also possible to put the directive into an FTL library (collection of macros and like in a template, that you include or import in other templates) using the new built-in: <#-- Maybe you have directives that you have implemented in FTL --> <#macro something> ... </#macro> <#-- Now you can't use <#macro upper>, but instead you can: --> <#assign upper = "com.example.UpperDirective"?new()>
Example 2 We will create a directive that executes its nested content again and again for the specified number of times (similarly to list directive), optionally separating the the output of the repetations with a <hr>-s. Let's call this directive "repeat". Example template: <#assign x = 1> <@repeat count=4> Test ${x} <#assign x = x + 1> </@repeat> <@repeat count=3 hr=true> Test </@repeat> <@repeat count=3; cnt> ${cnt}. Test </@repeat> Output: Test 1 Test 2 Test 3 Test 4 Test <hr> Test <hr> Test 1. Test 2. Test 3. Test The class: package com.example; import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.Map; import freemarker.core.Environment; import freemarker.template.SimpleNumber; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateNumberModel; /** * FreeMarker user-defined directive for repeating a section of a template, * optionally with separating the output of the repetations with * <tt>&lt;hr></tt>-s. * * * <p><b>Directive info</b></p> * * <p>Parameters: * <ul> * <li><code>count</code>: The number of repetations. Required! * Must be a non-negative number. If it is not a whole number then it will * be rounded <em>down</em>. * <li><code>hr</code>: Tells if a HTML "hr" element could be printed between * repetations. Boolean. Optional, defaults to <code>false</code>. * </ul> * * <p>Loop variables: One, optional. It gives the number of the current * repetation, starting from 1. * * <p>Nested content: Yes */ public class RepeatDirective implements TemplateDirectiveModel { private static final String PARAM_NAME_COUNT = "count"; private static final String PARAM_NAME_HR = "hr"; public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // --------------------------------------------------------------------- // Processing the parameters: int countParam = 0; boolean countParamSet = false; boolean hrParam = false; Iterator paramIter = params.entrySet().iterator(); while (paramIter.hasNext()) { Map.Entry ent = (Map.Entry) paramIter.next(); String paramName = (String) ent.getKey(); TemplateModel paramValue = (TemplateModel) ent.getValue(); if (paramName.equals(PARAM_NAME_COUNT)) { if (!(paramValue instanceof TemplateNumberModel)) { throw new TemplateModelException( "The \"" + PARAM_NAME_HR + "\" parameter " + "must be a number."); } countParam = ((TemplateNumberModel) paramValue) .getAsNumber().intValue(); countParamSet = true; if (countParam < 0) { throw new TemplateModelException( "The \"" + PARAM_NAME_HR + "\" parameter " + "can't be negative."); } } else if (paramName.equals(PARAM_NAME_HR)) { if (!(paramValue instanceof TemplateBooleanModel)) { throw new TemplateModelException( "The \"" + PARAM_NAME_HR + "\" parameter " + "must be a boolean."); } hrParam = ((TemplateBooleanModel) paramValue) .getAsBoolean(); } else { throw new TemplateModelException( "Unsupported parameter: " + paramName); } } if (!countParamSet) { throw new TemplateModelException( "The required \"" + PARAM_NAME_COUNT + "\" paramter" + "is missing."); } if (loopVars.length > 1) { throw new TemplateModelException( "At most one loop variable is allowed."); } // Yeah, it was long and boring... // --------------------------------------------------------------------- // Do the actual directive execution: Writer out = env.getOut(); if (body != null) { for (int i = 0; i < countParam; i++) { // Prints a <hr> between all repetations if the "hr" parameter // was true: if (hrParam && i != 0) { out.write("<hr>"); } // Set the loop variable, if there is one: if (loopVars.length > 0) { loopVars[0] = new SimpleNumber(i + 1); } // Executes the nested body (same as <#nested> in FTL). In this // case we don't provide a special writer as the parameter: body.render(env.getOut()); } } } }
Notices It's important that a TemplateDirectiveModel object usually should not be stateful. The typical mistake is the storing of the state of the directive call execution in the fields of the object. Think of nested calls of the same directive, or directive objects used as shared variables accessed by multiple threads concurrently. Unfortunatelly, TemplateDirectiveModel-s don't support passing parameters by position (rather than by name). This is fixed starting from FreeMarker 2.4.
Node variables node Java side tree nodes trees A node variable embodies a node in a tree structure. Node variables were introduced to help the handling of XML documents in the data-model, but they can be used for the modeling of other tree structures as well. For more information about nodes from the point of view of the template language read this earlier section. A node variable has the following properties, provided by the methods of TemplateNodeModel interface: Basic properties: TemplateSequenceModel getChildNodes(): A node has sequence of children (except if the node is a leaf node, in which case the method return an empty sequence or null). The child nodes should be node variables as well. TemplateNodeModel getParentNode(): A node has exactly 1 parent node, except if the node is root node of the tree, in which case the method returns null. Optional properties. If a property does not make sense in the concrete use case, the corresponding method should return null: String getNodeName(): The node name is the name of the macro, that handles the node when you use recurse and visit directives. Thus, if you want to use these directives with the node, the node name is required. String getNodeType(): In the case of XML: "element", "text", "comment", ...etc. This information, if available, is used by the recurse and visit directives to find the default handler macro for a node. Also it can be useful for other application specific purposes. String getNamespaceURI(): The node namespace (has nothing to do with FTL namespaces used for libraries) this node belongs to. For example, in the case of XML, this is the URI of the XML namespace the element or attribute belongs to. This information, if available, is used by the recurse and visit directives to find the FTL namespaces that store the handler macros. On the FTL side, the direct utilization of node properties is done with node built-ins, and with the visit and recurse macros. In most use cases, variables that implement TemplateNodeModel, implement other interfaces as well, since node variable properties just provide the basic infrastructure for navigating between nodes. For a concrete example, see how FreeMarker deals with XML.
Object wrappers object wrapper wrapper When you add something to a container, it may receive any java object as a parameter, not necessarily a TemplateModel, as you could see in the FreeMarker API. This is because the container implementation can silently replace that object with the appropriate TemplateModel object. For example if you add a String to the container, perhaps it will be replaced with a SimpleScalar instance which stores the same text. As for when the replacement occurs, it's the business of the container in question (i.e. the business of the class that implements the container interface), but it must happen at the latest when you get the subvariable, as the getter methods (according to the interfaces) return TemplateModel, not Object. For example, SimpleHash, SimpleSequence and SimpleCollection use the laziest strategy; they replace a non-TemplateModel subvariable with an appropriate TemplateModel object when you get the subvariable for the first time. As for what java objects can be replaced, and with what TemplateModel implementations, it is either handled by the container implementation itself, or it delegates this to an ObjectWrapper instance. ObjectWrapper is an interface that specifies one method: TemplateModel wrap(java.lang.Object obj). You pass in an Object, and it returns the corresponding TemplateModel object, or throws a TemplateModelException if this is not possible. The replacement rules are coded into the ObjectWrapper implementation. The most important ObjectWrapper implementations that the FreeMarker core provides are: ObjectWrapper.DEFAULT_WRAPPER: It replaces String with SimpleScalar, Number with SimpleNumber, List and array with SimpleSequence, Map with SimpleHash, Boolean with TemplateBooleanModel.TRUE or TemplateBooleanModel.FALSE, W3C DOM nodes with freemarker.ext.dom.NodeModel. For Jython objects, this wrapper will invoke freemarker.ext.jython.JythonWrapper. For all other objects, it will invoke BEANS_WRAPPER. ObjectWrapper.BEANS_WRAPPER: It can expose java Bean properties and other members of arbitrary objects using Java reflection. At least in FreeMarker 2.3, it is a freemarker.ext.beans.BeansWrapper instance; there is a separated chapter about it. For a concrete example, let's see how the SimpleXxx classes work. SimpleHash, SimpleSequence and SimpleCollection use DEFAULT_WRAPPER to wrap the subvariables (unless you pass in an alternative wrapper in their constructor). So this example demonstrates DEFAULT_WRAPPER in action: Map map = new HashMap(); map.put("anotherString", "blah"); map.put("anotherNumber", new Double(3.14)); List list = new ArrayList(); list.add("red"); list.add("green"); list.add("blue"); SimpleHash root = new SimpleHash(); // will use the default wrapper root.put("theString", "wombat"); root.put("theNumber", new Integer(8)); root.put("theMap", map); root.put("theList", list); Assuming that root is the data-model root, the resulting data-model is: (root) | +- theString = "wombat" | +- theNumber = 8 | +- theMap | | | +- anotherString = "blah" | | | +- anotherNumber = 3.14 | +- theList | +- (1st) = "red" | +- (2nd) = "green" | +- (3rd) = "blue" Note that the Object-s inside theMap and theList are accessible as subvariables too. This is because when you, say, try to access theMap.anotherString, then the SimpleHash (which is used as root hash here) will silently replace the Map (theMap) with a SimpleHash instance that uses the same wrapper as the root hash, so when you try to access the anotherString subvariable of it, it will replace that with a SimpleScalar. If you drop an ``arbitrary'' object into the data-model, DEFAULT_WRAPPER will invoke BEANS_WRAPPER to wrap the object: SimpleHash root = new SimpleHash(); // expose a "simple" java objects: root.put("theString", "wombat"); // expose an "arbitrary" java objects: root.put("theObject", new TestObject("green mouse", 1200)); Assuming this is TestObject: public class TestObject { private String name; private int price; public TestObject(String name, int price) { this.name = name; this.price = price; } // JavaBean properties // Note that public fields are not visible directly; // you must write a getter method for them. public String getName() {return name;} public int getPrice() {return price;} // A method public double sin(double x) { return Math.sin(x); } } The data-model will be: (root) | +- theString = "wombat" | +- theObject | +- name = "green mouse" | +- price = 1200 | +- number sin(number) So we can merge it with this template: ${theObject.name} ${theObject.price} ${theObject.sin(123)} Which will output: green mouse 1200 -0,45990349068959124 You have seen in earlier examples of this manual that we have used java.util.HashMap as root hash, and not SimpleHash or other FreeMarker specific class. It works because Template.process(...) automatically wraps the object you give as its data-model argument. It uses the object wrapper dictated by the Configuration level setting, object_wrapper (unless you explicitly specify an ObjectWrapper as its parameter). Thus, in simple FreeMarker application you need not know about TemplateModel-s at all. Note that the root need not be a java.util.Map. It can be anything that is wrapped so that it implements the TemplateHashModel interface. The factory default value of the object_wrapper setting is ObjectWrapper.DEFAULT_WRAPPER. If you want to change it to, say, ObjectWrapper.BEANS_WRAPPER, you can configure the FreeMarker engine (before starting to use it from other threads) like this: cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER); Note that you can set any object here that implements interface ObjectWrapper, so you can set your custom implementation as well. For TemplateModel implementations that wrap basic Java container types, as java.util.Map-s and java.util.List-s, the convention is that they use the same object wrapper to wrap their subvariables as their parent container does. Technically correctly said, they are instantiated by their parent container (so it has full control over the creation of them), and the parent container create them so they will use the same object wrapper as the parent itself. Thus, if BEANS_WRAPPER is used for the wrapping of the root hash, it will be used for the wrapping of the subvariables (and the subvariables of the subvariables, etc.) as well. This is exactly the same phenomenon as you have seen with theMap.anotherString earlier.
The Configuration Configuration This is just an overview. See the FreeMarker Java API documentation for the details.
Basics A configuration is an object that stores your common (application level) settings and defines certain variables that you want to be available in all templates. Also it deals with the creation and caching of Template instances. A configuration is a freemarker.template.Configuration instances, that you can create with its constructor. An application typically uses only a single shared Configuration instance. Configurations are used by the Template methods, especially by process method. Each Template instance has exactly one Configuration instance associated with it, which is assigned to the Template instance by the Template constructor; you can specify a Configuration instance as its parameter. Usually you obtain Template instances with Configuration.getTemplate (not by directly calling the Template constructor), in which case the associated Configuration instance will be the one whose getTemplate method has been called.
Shared variables shared variable Shared variables are variables that are defined for all templates. You can add shared variables to the configuration with the setSharedVariable methods: Configuration cfg = new Configuration(); ... cfg.setSharedVariable("wrap", new WrapDirective()); cfg.setSharedVariable("company", "Foo Inc."); // Using ObjectWrapper.DEFAULT_WRAPPER In all templates that use this configuration, an user-defined directive with name wrap and a string with name company will be visible in the data-model root, so you don't have to add them to the root hash again and again. A variable in the root object that you pass to the Template.process will hide the shared variable with the same name. Never use TemplateModel implementation that is not thread-safe for shared variables, if the configuration is used by multiple threads! This is the typical situation for Servlet based Web sites. Due to backward compatibility heritage, the set of shared variables is initially (i.e., for a new Configuration instance) not empty. It contains the following user-defined directives (they are "user-defined" in the sense that you use @ to call them instead of #): name class capture_output freemarker.template.utility.CaptureOutput compress freemarker.template.utility.StandardCompress html_escape freemarker.template.utility.HtmlEscape normalize_newlines freemarker.template.utility.NormalizeNewlines xml_escape freemarker.template.utility.XmlEscape
Settings setting Settings are named values that influence the behavior of FreeMarker. Examples of settings are: locale, number_format Settings stored in Configuration instance can be overridden in a Template instance. For example you set "en_US" for the locale setting in the configuration, then the locale in all templates that use this configuration will be "en_US", except in templates where the locale was explicitly specified differently (see localization). Thus, values in a Configuration serve as defaults that can be overridden in a per template manner. The value comes from Configuration instance or Template instance can be further overridden for a single Template.process call. For each such call a freemarker.core.Environment object is created internally that holds the runtime environment of the template processing, including the setting values that were overridden on that level. The values stored there can even be changed during the template processing, so a template can set settings itself, like switching locale at the middle of the output. This can be imagined as 3 layers (Configuration, Template, Environment) of settings, where the topmost layer that contains the value for a certain setting provides the effective value of that setting. For example (settings A to F are just imaginary settings for this example): Setting A Setting B Setting C Setting D Setting E Setting F Layer 3: Environment 1 - - 1 - - Layer 2: Template 2 2 - - 2 - Layer 1: Configuration 3 3 3 3 - - The effective value of settings will be: A = 1, B = 2, C = 3, D = 1, E = 2. The F setting is probably null, or it throws exception when you try to get it. Let's see exactly how to set settings: Configuration layer: In principle you set the settings with the setter methods of the Configuration object, fore example: Configuration myCfg = new Configuration(); myCfg.setLocale(java.util.Locale.ITALY); myCfg.setNumberFormat("0.####"); You do it before you start to actually use the Configuration object (typically, when you initialize the application); you should treat the object as read-only after that. In practice, in most Web application frameworks you have to specify the setting in a framework-specific configuration file that require specifying setting as String name-value pairs (like in a .properties file). In that case the authors of the frameworks most probably use the setSetting(String name, String value) method of Configuration; see available setting names and the format of the values in the API doc of setSetting. Example for Spring Framework: <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="freemarkerSettings"> <props> <prop key="locale">it_IT</prop> <prop key="number_format">0.####</prop> </props> </property> </bean> Note that this kind of configuring (String key-value pairs) is unfortunately limited compared to directly using the API of Configuration. Template layer: You shouldn't set settings here, unless you manage the Template objects instead of a freemarker.cache.TemplateCache, in which case you should set the setting before the Template object is first used, and then treat the Template object as read-only. Environment layer: There are two ways doing it: With Java API: Use the setter methods of the Environment object. Certainly you want to do that just before the processing of the template is started, and then you run into the problem that when you call myTemplate.process(...) it creates the Environment object internally and the immediately processes the template, so you had no chance. The solution is that this two steps can be separated like this: Environment env = myTemplate.createProcessingEnvironment(root, out); env.setLocale(java.util.Locale.ITALY); env.setNumberFormat("0.####"); env.process(); // process the template Directly in the Template: Use the setting directive, for example: <#setting locale="it_IT"> <#setting number_format="0.####"> There are no restriction regarding when can you change the settings in this layer. To see the list of supported settings, please read the following parts of the FreeMarker Java API documentation: Setter methods of freemarker.core.Configurable for the settings that are in all three layers Setter methods of freemarker.template.Configuration for the settings that are available only in the Configuration layer freemarker.core.Configurable.setSetting(String, String) for settings that are available in all three layers and are writable with String key-value pairs. freemarker.template.Configuration.setSetting(String, String) for settings that are available only in the Configuration layer and are writable with String key-value pairs.
Template loading loading templates template loading storing templates
Template loaders template loaders Template loaders are objects that load raw textual data based on abstract template paths like "index.ftl" or "products/catalog.ftl". It is up to the concrete template loader object what source does it use to fetch the requested data (files in a directory, data base, etc.). When you call cfg.getTemplate (where cfg is a Configuration instance), FreeMarker ask the template loader you have set up for the cfg to return the text for the given template path, and then FreeMarker parses that text as template.
Built-in template loaders You can set up three template loading methods in the Configuration using the following convenience methods. (Each method will create a template loader object internally and set up the Configuration instance to use that.) void setDirectoryForTemplateLoading(File dir); or void setClassForTemplateLoading(Class cl, String prefix); or void setServletContextForTemplateLoading(Object servletContext, String path); The first method above sets an explicit directory on the file system from which to load templates. Needless to say perhaps, the File parameter must be an existing directory. Otherwise, an exception will be thrown. The second call takes a Class as a parameter and a prefix. This is for when you want to load templates via the same mechanism that a java ClassLoader uses to load classes. This means that the class you pass in will be used to call Class.getResource() to find the templates. The prefix parameter is prepended to the name of the template. The classloading mechanism will very likely be the preferred means of loading templates for production code, since loading from the classpath mechanism is usually more foolproof than specifying an explicit directory location on the file system. It is also nicer in a final application to keep everything in a .jar file that the user can simply execute directly and have all the icons and text and everything else inside the .jar file. The third call takes the context of your web application, and a base path, which is interpreted relative to the web application root directory (that's the parent of the WEB-INF directory). This loader will load the templates from the web application directory. Note that we refer to "directory" here although this loading method works even for unpacked .war files since it uses ServletContext.getResource() to access the templates. If you omit the second parameter (or use ""), you can simply store the static files (.html, .jpg, etc.) mixed with the .ftl files, just .ftl files will be sent to the client processed. Of course, you must set up a Servlet for the *.ftl uri-pattern in WEB-INF/web.xml for this, otherwise the client will get the templates as is, and thus may see confidential content! You should not use empty path if this is a problem for your site, rather you should store the templates somewhere inside the WEB-INF directory, so the raw templates are never served accidentally. This mechanism will very likely be the preferred means of loading templates for servlet applications, since the templates can be updated without restarting the web application, while this often doesn't work with the class-loader mechanism.
Loading templates from multiple locations If you need to load templates from multiple locations, you have to instantiate the template loader objects for every location, wrap them into a special template loader named MultiTemplateLoader and finally pass that loader to the setTemplateLoader(TemplateLoader loader) method of Configuration. Here's an example for loading templates from two distinct directories and with the class-loader: import freemarker.cache.*; // template loaders live in this package ... FileTemplateLoader ftl1 = new FileTemplateLoader(new File("/tmp/templates")); FileTemplateLoader ftl2 = new FileTemplateLoader(new File("/usr/data/templates")); ClassTemplateLoader ctl = new ClassTemplateLoader(getClass(), ""); TemplateLoader[] loaders = new TemplateLoader[] { ftl1, ftl2, ctl }; MultiTemplateLoader mtl = new MultiTemplateLoader(loaders); cfg.setTemplateLoader(mtl); Now FreeMarker will try to load templates from /tmp/templates directory, and if it does not find the requested template there, it will try to load that from /usr/data/templates, and if it still does not find the requested template, then it tries to load that with the class-loader.
Loading templates from other sources If none of the built-in class loaders are good for you, you will have to write your own class that implements the freemarker.cache.TemplateLoader interface and pass it to the setTemplateLoader(TemplateLoader loader) method of Configuration. Please read the API JavaDoc for more information. If your template source accesses the templates through an URL, you needn't implement a TemplateLoader from scratch; you can choose to subclass freemarker.cache.URLTemplateLoader instead and just implement the URL getURL(String templateName) method.
The template path path template path It is up to the template loader how it interprets template paths. But to work together with other components there are restrictions regarding the format of the path. In general, it is strongly recommended that template loaders use URL-style paths. The path must not use /, ./ and ../ and :// with other meaning as they have in URL paths (or in UN*X paths). The characters * and ? are reserved. Also, the template loader must not want paths starting with /; FreeMarker will never call template loader with such path. Note that FreeMarker always normalizes the paths before passing them to the template loader, so the paths do not contain /../ and such, and are relative to the imaginary template root directory. Note that FreeMarker template loading always uses slash (not backslash) regardless of the host OS.
Template caching caching template caching FreeMarker caches templates (assuming you use the Configuration methods to create Template objects). This means that when you call getTemplate, FreeMarker not only returns the resulting Template object, but stores it in a cache, so when next time you call getTemplate with the same (or equivalent) path, it just returns the cached Template instance, and will not load and parse the template file again. If you change the template file, then FreeMarker will re-load and re-parse the template automatically when you get the template next time. However, since checking if the file has been changed can be time consuming, there is a Configuration level setting called ``update delay''. This is the time that must elapse since the last checking for a newer version of a certain template before FreeMarker will check that again. This is set to 5 seconds by default. If you want to see the changes of templates immediately, set it to 0. Note that some template loaders may have problems with template updating. For example, class-loader based template loaders typically do not notice that you have changed the template file. A template will be removed from the cache if you call getTemplate and FreeMarker realizes that the template file has been removed meanwhile. Also, if the JVM thinks that it begins to run out of memory, by default it can arbitrarily drop templates from the cache. Furthermore, you can empty the cache manually with the clearTemplateCache method of Configuration. The actual strategy of when a cached template should be thrown away is pluggable with the cache_storage setting, by which you can plug any CacheStorage implementation. For most users freemarker.cache.MruCacheStorage will be sufficient. This cache storage implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum (strongly referenced items can't be dropped by the JVM, as opposed to softly referenced items). When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specified maximum. The size of the strong and soft parts can be specified with the constructor. For example, set the size of the strong part to 20, and the size of soft part to 250: cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(20, 250)) Or, since MruCacheStorage is the default cache storage implementation: cfg.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:20, soft:250"); When you create a new Configuration object, initially it uses an MruCacheStorage where maxStrongSize is 0, and maxSoftSize is Integer.MAX_VALUE (that is, in practice, infinite). But using non-0 maxStrongSize is maybe a better strategy for high load servers, since it seems that, with only softly referenced items, JVM tends to cause just higher resource consumption if the resource consumption was already high, because it constantly throws frequently used templates from the cache, which then have to be re-loaded and and re-parsed.
Error handling error handling exception handling
The possible exceptions The exceptions that can occur regarding FreeMarker could be classified like this: Exceptions occurring when you configure FreeMarker: Typically you configure FreeMarker only once in your application, when your application initializes itself. Of course, during this, exceptions can occur, as it is obvious from the FreeMarker API... Exceptions occurring when loading and parsing templates: When you call Configuration.getTemplate(...), FreeMarker has to load the template file into the memory and parse it (unless the template is already cached in that Configuration object). During this, two kind of exceptions can occur: IOException because the template file was not found, or other I/O problem occurred while trying to read it, for example you have no right to read the file, or there are disk errors. The emitter of these errors is the TemplateLoader object, which is plugged into the Configuration object. (For the sake of correctness: When I say ``file'' here, that's a simplification. For example, templates can be stored in a table of a relational database as well. This is the business of the TemplateLoader.) freemarker.core.ParseException because the template file is syntactically incorrect according the rules of the FTL language. The point is that this error occurs when you obtain the Template object (Configuration.getTemplate(...)), and not when you execute (Template.process(...)) the template. This exception is an IOException subclass. Exceptions occurring when executing (processing) templates, that is, when you call Template.process(...). Two kind of exceptions can occur: IOException because there was an error when trying to write into the output writer. freemarker.template.TemplatException because other problem occurred while executing the template. For example, a frequent error is when a template refers to a variable which is not existing. Be default, when a TemplatException occurs, FreeMarker prints the FTL error message and the stack trace to the output writer with plain text format, and then aborts the template execution by re-throwing the TemplatException, which then you can catch as Template.process(...) throws it. But this behavior can be customized. FreeMarker always logs TemplatException-s.
Customizing the behavior regarding TemplatException-s TemplateException-s thrown during the template processing are handled by the freemarker.template.TemplateExceptionHandler object, which is plugged into the Configuration object with its setTemplateExceptionHandler(...) mehod. The TemplateExceptionHandler contains 1 method: void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException; Whenever a TemplateException occurs, this method will be called. The exception to handle is passed with the te argument, the runtime environment of the template processing is accessible with the env argument, and the handler can print to the output using the out argument. If the method throws exception (usually it re-throws te), then the template processing will be aborted, and Template.process(...) will throw the same exception. If handleTemplateException doesn't throw exception, then template processing continues as if nothing had happen, but the statement that caused the exception will be skipped (see more later). Of course, the handler can still print an error indicator to the output. In any case, before the TemplateExceptionHandler is invoked, FreeMarker will log the exception. Let's see how FreeMarker skips ``statements'' when the error handler doesn't throw exception, through examples. Assume we are using this template exception handler: class MyTemplateExceptionHandler implements TemplateExceptionHandler { public void handleTemplateException(TemplateException te, Environment env, java.io.Writer out) throws TemplateException { try { out.write("[ERROR: " + te.getMessage() + "]"); } catch (IOException e) { throw new TemplateException("Failed to print error message. Cause: " + e, env); } } } ... cfg.setTemplateExceptionHandler(new MyTemplateExceptionHandler()); If an error occurs in an interpolation which is not inside an FTL tag (that is, not enclosed into <#...> or <@...>), then the whole interpolation will be skipped. So this template (assuming that badVar is missing from the data-model): a${badVar}b will print this if we use the MyTemplateExceptionHandler: a[ERROR: Expression badVar is undefined on line 1, column 4 in test.ftl.]b This template will print the same (except that the column number will differ...): a${"moo" + badVar}b since, as it was written, the whole interpolation is skipped if any error occurs inside it. If an error occurs when evaluating the value of a parameter for a directive call, or if there are other problems with the parameter list, or if an error occurs when evaluating exp in <@exp ...>, or if the value of exp is not an user-defined directive, then the whole directive call is skipped. For example this: a<#if badVar>Foo</#if>b will print this: a[ERROR: Expression badVar is undefined on line 1, column 7 in test.ftl.]b Note that the error occurred in the if start-tag (<#if badVar>), but the whole directive call was skipped. Logically, the nested content (Foo) was skipped with this, since the nested content is handled (printed) by the enclosing directive (if). The output will be the same with this (except that the column number will differ...): a<#if "foo${badVar}" == "foobar">Foo</#if>b since, as it was written, the whole directive calling will be skipped if any error occurs during the parameter evaluation. The directive call will not be skipped if the error occurs after the execution of the directive was already started. That is, if an error occurs in the nested content: a <#if true> Foo ${badVar} Bar </#if> c or in the macro definition body: a <@test /> b <#macro test> Foo ${badVar} Bar </#macro> the output will be something like: a Foo [ERROR: Expression badVar is undefined on line 4, column 5 in test.ftl.] Bar c FreeMarker comes with these prewritten error handlers: TemplateExceptionHandler.DEBUG_HANDLER: Prints stack trace (includes FTL error message and FTL stack trace) and re-throws the exception. This is the default handler (that is, it is initially prugged into all new Configuration objects). TemplateExceptionHandler.HTML_DEBUG_HANDLER: Same as DEBUG_HANDLER, but it formats the stack trace so that it will be readable with Web browsers. Recommended over DEBUG_HANDLER when you generate HTML pages. TemplateExceptionHandler.IGNORE_HANDLER: Simply suppresses all exceptions (but remember, FreeMarker will still log them). It does nothing to handle the event. It does not re-throw the exception. TemplateExceptionHandler.RETHROW_HANDLER: Simply re-throws all exceptions, it doesn't do anything else. This handler can be good for Web applications (assuming you don't want to continue template processing after exception), because it gives the most control to the Web application over page generation on error conditions (since FreeMarker doesn't print anything to the output about the error). For more information about handling errors in Web applications see the FAQ.
Explicit error handling in templates Although it has nothing to do with the FreeMarker configuration (the topic of this chapter), for the sake of completeness it is mentioned here that you can handle errors directly in templates as well. This is usually a bad practice (try keep templates simple and non-technical), but nonetheless necessary sometimes: Handling missing/null variables: Surviving malfunctioning ``portlets'' and such expendable page sections:
Miscellaneous This is just an introductory guide. See the FreeMarker Java API documentation for the details.
Variables variables This chapter explains what happens when a template tries to access a variable, and how the variables are stored. When you call Template.process it will internally create an Environment object that will be in use until process returns. This object stores the runtime state of template processing. Among other things, it stores the variables created by the template with directives like assign, macro, local or global. It never tries to modify the data-model object that you pass to the process call, nor does it create or replace shared variables stored in the configuration. When you try to read a variable, FreeMarker will seek the variable in this order, and stops when it finds a variable with the right name: In the Environment: If you are in a loop, in the set of loop variables. Loop variables are the variables created by directives like list. If you are inside a macro, in the local variable set of the macro. Local variables can be created with the local directive. Also, the parameters of macros are local variables. In the current namespace. You can put variables into a namespace with the assign directive. In the set of variables created with global directive. FTL handles these variables as if they were normal members of the data-model. That is, they are visible in all namespaces, and you can access them as if they would be in the data-model. In the data-model object you have passed to the process method In the set of shared variables stored in the Configuration In practice, from the viewpoint of template authors these 6 layers are only 4 layers, since from that viewpoint the last 3 layers (variables created with global, the actual data-model object, shared variables) together constitute the set of global variables. Note that it is possible to get variables from a specific layer in FTL with special variables.
Charset issues charset encoding FreeMarker, as most Java applications, works with "UNICODE text" (UTF-16). Nonetheless, there are situations when it must deal with charsets, because it has to exchange data with the outer world that may uses various charsets.
The charset of the input When FreeMarker has to load a template file (or an unparsed text file), then it must know the charset of the file, since files are just raw byte arrays. You can use the encoding setting to specify the charset. This setting takes effect only when FreeMarker loads a template (parsed or unparsed) with the getTemplate method of Configuration. Note that the include directive uses this method internally, so the value of the encoding setting is significant for an already loaded template if the template contains include directive call. The getter and setter method of the encoding setting is special in the first (configuration) layer. The getter method guesses the return value based on a Locale passed as parameter; it looks up the encoding in a table that maps locales to encodings (called encoding map), and if the locale was not found there, it returns the default encoding. You can fill the encoding map with the setEncoding(Locale locale, String encoding) method of the configuration; the encoding map is initially empty. The default encoding is initially the value of the file.encoding system property, but you can set a different default with the setDefaultEncoding method. You can give the charset directly by overriding the encoding setting in the template layer or runtime environment layer (When you specify an encoding as the parameter of getTemplate method, you override the encoding setting in the template layer.). If you don't override it, the effective value will be what the configuration.getEncoding(Locale) method returns for the effective value of the locale setting. Also, instead of relying on this charset guessing mechanism, you can specify the charset of the template in the template file itself, with the ftl directive. You may wonder what charset you should choose for the templates. It primarily depends on the tools (as text editors) that you want to use to create and modify templates. In principle, using UTF-8 is the best, but currently (2004) only a few tools supports it, actually most of them doesn't even know about charsets. So in that case you should use the widely used charset of your language, which is probably also the default charset of you working environment. Note that the charset of the template is independent from the charset of the output that the tempalte generates (unless the enclosing software deliberately sets the output charset to the same as the template charset).
The charset of the output The output_encoding setting/variable and the url built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. output encoding output charset In principle FreeMarker does not deal with the charset of the output, since it writes the output to a java.io.Writer. Since the Writer is made by the software that encapsulates FreeMarker (such as a Web application framework), the output charset is controlled by the encapsulating software. Still, FreeMarker has a setting called output_encoding (starting from FreeMarker version 2.3.1). The enclosing software should set this setting (to the charset that the Writer uses), to inform FreeMarker what charset is used for the output (otherwise FreeMarker can't find it out). Some features, such as the url built-in, and the output_encoding special variable utilize this information. Thus, if the enclosing software doesn't set this setting then FreeMarker features that need to know the output charset can't be used. If you write software that will use FreeMarker, you may wonder what output charset should you choose. Of course it depends on the consumer of the FreeMarker output, but if the consumer is flexible regarding this question, then the common practice is either using the charset of the template file for the output, or using UTF-8. Using UTF-8 is usually a better practice, because arbitrary text may comes from the data-model, which then possibly contains characters that couldn't be encoded with the charset of the template. FreeMarker settings can be set for each individual template processing if you use Template.createProcessingEnvironment(...) plus Environment.process(...) instead of Template.process(...). Thus, you can set the output_encoding setting for each template execution independently: Writer w = new OutputStreamWriter(out, outputCharset); Environment env = template.createProcessingEnvironment(dataModel, w); env.setOutputEncoding(outputCharset); env.process();
Multithreading multithreading thread-safety In a multithreaded environment Configuration instances, Template instances and data-models should be handled as immutable (read-only) objects. That is, you create and initialize them (for example with set... methods), and then you don't modify them later (e.g. you don't call set...). This allows us to avoid expensive synchronized blocks in a multithreaded environment. Beware with Template instances; when you get a Template instance with Configuration.getTemplate, you may get an instance from the template cache that is already used by other threads, so do not call its set... methods (calling process is of course fine). The above restrictions do not apply if you access all objects from the same single thread only. It is impossible to modify the data-model object or a shared variable with FTL, unless you put methods (or other objects) into the data-model that do that. We discourage you from writing methods that modify the data-model object or the shared variables. Try to use variables that are stored in the environment object instead (this object is created for a single Template.process call to store the runtime state of processing), so you don't modify data that are possibly used by multiple threads. For more information read:
Bean wrapper wrapping reflection wrapping beans beans wrapping The freemarker.ext.beans.BeansWrapper is an object wrapper that was originally added to FreeMarker so arbitrary POJO-s (Plain Old Java Objects) can be wrapped into TemplateModel interfaces. Since then it has becomed the normal way of doing things, and in fact the DefaultObjectWrapper itself is a BeansWrapper extension. So everything described here goes for the DefaultObjectWrapper too, except that the DefaultObjectWrapper will wrap String, Number, Date, array, Collection (like List), Map, Boolean and Iterator objects with the freemarker.template.SimpleXxx classes, and W3C DOM nodes with freemarker.ext.dom.NodeModel (more about wrapped W3C DOM...), so for those the above described rules doesn't apply. You will want to use BeansWrapper instead of DefaultObjectWrapper when any of these stands: The Collection-s and Map-s of the model should be allowed to be modified during template execution. (DefaultObjectWrapper prevents that, since it creates a copy of the collections when they are wrapped, and the copies will be read-only.) If the identity of the array, Collection and Map objects must be kept when they are passed to a wrapped object's method in the template. That is, if those methods must get exactly the same object that was earlier wrapped. If the Java API of the earlier listed classes (String, Map, List ...etc) should be visible for the templates. Even with BeansWrapper, they are not visible by default, but it can be achieved by setting the exposure level (see later). Note that this is usually a bad practice; try to use the built-ins (like foo?size, foo?upper, foo?replace('_', '-') ...etc) instead of the Java API. Below is a summary of the TemplateModel-s that the BeansWrapper creates. Let's assume that the object is called obj before wrapping, and model after wrapping for the sake of the following discussion.
TemplateHashModel functionality Every object will be wrapped into a TemplateHashModel that will expose JavaBeans properties and methods of the object. This way, you can use model.foo in the template to invoke obj.getFoo() or obj.isFoo() methods. (Note that public fields are not visible directly; you must write a getter method for them.) Public methods are also retrievable through the hash model as template method models, therefore you can use the model.doBar() to invoke object.doBar(). More on this on discussion of method model functionality. If the requested key can not be mapped to a bean property or method, the framework will attempt to locate the so-called "generic get method", that is a method with signature public any-return-type get(String) or public any-return-type get(Object) and invoke that method with the requested key. Note that this allows convenient access to mappings in a java.util.Map and similar classes - as long as the keys of the map are Strings and some property or method name does not shadow the mapping. (There is a solution to avoid shadowing, read on.) Also note that the models for java.util.ResourceBundle objects use the getObject(String) as the generic get method. If you call setExposeFields(true) on a BeansWrapper instance, it will also expose public, non-static fields of classes as hash keys and values. I.e. if foo is a public, non-static field of the class Bar, and bar is a template variable wrapping an instance of Bar, then bar.foo expression will evaluate as the value of the field foo of the bar object. The public fields in all superclasses of the class are also exposed.
A word on security By default, you will not be able to access several methods that are considered not safe for templating. For instance, you can't use synchronization methods (wait, notify, notifyAll), thread and thread group management methods (stop, suspend, resume, setDaemon, setPriority), reflection (Field setXxx methods, Method.invoke, Constructor.newInstance, Class.newInstance, Class.getClassLoader etc.) and various dangerous methods in System and Runtime classes (exec, exit, halt, load, etc.). The BeansWrapper has several security levels (called "levels of method exposure"), and the default called EXPOSE_SAFE is probably suited for most applications. There is a no-safeguard level called EXPOSE_ALL that allows you to call even the above unsafe methods, and a strict level EXPOSE_PROPERTIES_ONLY that will expose only bean property getters. Finally, there is a level named EXPOSE_NOTHING that will expose no properties and no methods. The only data you will be able to access through hash model interface in this case are items in maps and resource bundles, as well as objects returned from a call to generic get(Object) or get(String) methods - provided the affected objects have such method.
TemplateScalarModel functionality Models for java.lang.String objects will implement TemplateScalarModel whose getAsString() method simply delegates to toString(). Note that wrapping String objects into Bean wrappers provides much more functionality than just them being scalars: because of the hash interface described above, the models that wrap Strings also provide access to all String methods (indexOf, substring, etc.).
TemplateNumberModel functionality Model wrappers for objects that are instances of java.lang.Number implement TemplateNumberModel whose getAsNumber() method returns the wrapped number object. Note that wrapping Number objects into Bean wrappers provides much more functionality than just them being number models: because of the hash interface described above, the models that wrap Numbers also provide access to all their methods.
TemplateCollectionModel functionality Model wrappers for native Java arrays and all classes that implement java.util.Collection will implement TemplateCollectionModel and thus gain the additional capability of being usable through list directive.
TemplateSequenceModel functionality Model wrappers for native Java arrays and all classes that implement java.util.List will implement TemplateSequenceModel and thus their elements will be accessible by index using the model[i] syntax. You can also query the length of the array or the size of the list using the model?size built-in. Also, every method that takes a single parameter that is assignable through reflective method invocation from a java.lang.Integer (these are int, long, float, double, java.lang.Object, java.lang.Number, and java.lang.Integer) also implements this interface. What this means is that you have a convenient way for accessing the so-called indexed bean properties: model.foo[i] will translate into obj.getFoo(i).
TemplateMethodModel functionality All methods of an object are represented as TemplateMethodModelEx objects accessible using a hash key with method name on their object's model. When you call a method using model.method(arg1, arg2, ...) the arguments are passed to the method as template models. The method will first try to unwrap them - see below for details about unwrapping. These unwrapped arguments are then used for the actual method call. In case the method is overloaded, the most specific method will be selected using the same rules that are used by the Java compiler to select a method from several overloaded methods. In case that no method signature matches the passed parameters, or that no method can be chosen without ambiguity, a TemplateModelException is thrown. Methods of return type void return TemplateModel.NOTHING, so they can be safely called with the ${obj.method(args)} syntax. Models for instances of java.util.Map also implement TemplateMethodModelEx as a means for invoking their get() method. As it was discussed previously, you can use the hash functionality to access the "get" method as well, but it has several drawbacks: it's slower because first property and method names are checked for the key; keys that conflict with property and method names will be shadowed by them; finally you can use String keys only with that approach. In contrast, invoking model(key) translates to model.get(key) directly: it's faster because there's no property and method name lookup; it is subject to no shadowing; and finally it works for non-String keys since the argument is unwrapped just as with ordinary method calls. In effect, model(key) on a Map is equal to model.get(key), only shorter to write. Models for java.util.ResourceBundle also implement TemplateMethodModelEx as a convenient way of resource access and message formatting. A single-argument call to a bundle will retrieve the resource with the name that corresponds to the toString() value of the unwrapped argument. A multiple-argument call to a bundle will also retrieve the resource with the name that corresponds to the toString() value of the unwrapped argument, but it will use it as a format pattern and pass it to java.text.MessageFormat using the unwrapped values of second and later arguments as formatting parameters. MessageFormat objects will be initialized with the locale of the bundle that originated them.
Unwrapping rules When invoking a Java method from a template, its arguments need to be converted from template models back to Java objects. Assuming that the target type (the declared type of the method's formal parameter) is denoted as T, the following rules are tried in the following order: If the model is the null model for this wrapper, Java null is returned. If the model implements AdapterTemplateModel, the result of model.getAdaptedObject(T) is returned if it is instance of T or it is a number and can be converted to T using numeric coercion as described three bullets lower. All models created by the BeansWrapper are themselves AdapterTemplateModel implementations, so unwrapping a model that was created by BeansWrapper for an underlying Java object always yields the original Java object. If the model implements the deprecated WrapperTemplateModel, the result of model.getWrappedObject() is returned if it is instance of T or it is a number and can be converted to T using numeric coercion as described two bullets lower. If T is java.lang.String, then if model implements TemplateScalarModel its string value is returned. Note that if the model doesn't implement TemplateScalarModel we don't attempt to automatically convert the model to string using String.valueOf(model). You'll have to use the ?string built-in explicitly to pass non-scalars as strings. If T is a primitive numeric type or java.lang.Number is assignable from T, and model implements TemplateNumberModel, then its numeric value is returned if it is instance of T or its boxing type (if T is primitive type). Otherwise, if T is a built-in Java numeric type (primitive type or a standard subclass of java.lang.Number, including BigInteger and BigDecimal) a new object of class T or its boxing type is created with the number model's appropriately coerced value. If T is boolean or java.lang.Boolean, and model implements TemplateBooleanModel, then its boolean value is returned. If T is java.util.Map and the model implements TemplateHashModel, then a special Map representation of the hash model is returned. If T is java.util.List and the model implements TemplateSequenceModel, then a special List representation of the sequence model is returned. If T is java.util.Set and the model implements TemplateCollectionModel, then a special Set representation of the collection model is returned. If T is java.util.Collection or java.lang.Iterable and the model implements either TemplateCollectionModel or TemplateSequenceModel, then a special Set or List representation of the collection or sequence model (respectively) is returned. If T is a Java array type and the model implements TemplateSequenceModel, then a new array of the specified type is created and its elements unwrapped into the array recursively using the array's component type as T. If T is char or java.lang.Character, and model implements TemplateScalarModel, and its string representation contains exactly one character, then a java.lang.Character with that value is retured. If java.util.Date is assignable from T, and model implements TemplateDateModel, and its date value is instance of T, then its date value is returned. If model is a number model, and its numeric value is instance of T, the numeric value is returned. You can have a custom subclass of java.lang.Number that implements a custom interface, and T might be that interface. (*) If model is a date model, and its date value is instance of T, the date value is returned. Similar consideration as for (*) If model is a scalar model, and T is assignable from java.lang.String, the string value is returned. This covers cases when T is java.lang.Object, java.lang.Comparable, and java.io.Serializable (**) If model is a boolean model, and T is assignable from java.lang.Boolean, the boolean value is returned. Same as (**) If model is a hash model, and T is assignable from freemarker.ext.beans.HashAdapter, a hash adapter is returned. Same as (**) If model is a sequence model, and T is assignable from freemarker.ext.beans.SequenceAdapter, a sequence adapter is returned. Same as (**) If model is a collection model, and T is assignable from freemarker.ext.beans.SetAdapter, a set adapter for the collection is returned. Same as (**) If the model is instance of T, the model itself is returned. This covers the case where the method explicitly declared a FreeMarker-specific model interface, as well as allows returning directive, method and transform models when java.lang.Object is requested. An exception signifying no conversion is possible is thrown.
Accessing static methods static method accessing from templates The TemplateHashModel returned from BeansWrapper.getStaticModels() can be used to create hash models for accessing static methods and fields of an arbitrary class. BeansWrapper wrapper = BeansWrapper.getDefaultInstance(); TemplateHashModel staticModels = wrapper.getStaticModels(); TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get("java.io.File"); And you will get a template hash model that exposes all static methods and static fields (both final and non-final) of the java.lang.System class as hash keys. Suppose that you put the previous model in your root model: root.put("File", fileStatics); From now on, you can use ${File.SEPARATOR} to insert the file separator character into your template, or you can even list all roots of your file system by: <#list File.listRoots() as fileSystemRoot>...</#list> Of course, you must be aware of the potential security issues this model brings. You can even give the template authors complete freedom over which classes' static methods they use by placing the static models hash into your template root model with root.put("statics", BeansWrapper.getDefaultInstance().getStaticModels()); This object exposes just about any class' static methods if it's used as a hash with class name as the key. You can then use expression like ${statics["java.lang.System"].currentTimeMillis()} in your template. Note, however that this has even more security implications, as someone could even invoke System.exit() using this model if the method exposure level is weakened to EXPOSE_ALL. Note that in above examples, we always use the default BeansWrapper instance. This is a convenient static wrapper instance that you can use in most cases. You are also free to create your own BeansWrapper instances and use them instead especially when you want to modify some of its characteristics (like model caching, security level, or the null model representation).
Accessing enums enum The TemplateHashModel returned from BeansWrapper.getEnumModels() can be used to create hash models for accessing values of enums on JRE 1.5 or later. (An attempt to invoke this method on an earlier JRE will result in an UnsupportedOperationException.) BeansWrapper wrapper = BeansWrapper.getDefaultInstance(); TemplateHashModel enumModels = wrapper.getEnumModels(); TemplateHashModel roundingModeEnums = (TemplateHashModel) enumModels.get("java.math.RoundingMode"); And you will get a template hash model that exposes all enum values of the java.math.RoundingMode class as hash keys. Suppose that you put the previous model in your root model: root.put("RoundingMode", roundingModeEnums); From now on, you can use RoundingMode.UP as an expression to reference the UP enum value in your template. You can even give the template authors complete freedom over which enum classes they use by placing the enum models hash into your template root model with root.put("enums", BeansWrapper.getDefaultInstance().getEnumModels()); This object exposes any enum class if it's used as a hash with class name as the key. You can then use expression like ${enums["java.math.RoundingMode"].UP} in your template. The exposed enum values can be used as scalars (they'll delegate to their toString() method), and can be used in equality and inequality comparisons as well. Note that in above examples, we always use the default BeansWrapper instance. This is a convenient static wrapper instance that you can use in most cases. You are also free to create your own BeansWrapper instances and use them instead especially when you want to modify some of its characteristics (like model caching, security level, or the null model representation).
Logging logging FreeMarker integrates with the following logging packages: SLF4J, Apache Commons Logging, Log4J, Avalon LogKit, and java.util.logging (Java 1.4 and above). By default, FreeMarker will look for the following logging packages in this order, and will automatically use the first package it finds: [2.4 - un-remark this] SLF4J, Apache Commons Logging, Log4J, Avalon, java.util.logging. However, if you call the static selectLoggerLibrary method on the freemarker.log.Logger class with appropriate parameter and before using any FreeMarker classes that log messages, you can explicitly select a logger package, or even disable the logging. See the API documentation for more details. Prior to FreeMarker 2.4, SLF4J and Apache Commons Logging aren't searched automatically due to backward compatibility constraints, so to use one of them you must do this: import freemarker.log.Logger; ... // IMPORTANT: This should be executed before using other FreeMarker classes! Logger.selectLoggerLibrary(Logger.LIBRARY_SLF4J); // or Logger.LIBRARY_COMMONS ... Doing this is recommended, because starting from 2.4 SLF4J will be used by default if present, otherwise Apache Commons Logging if present, otherwise Log4J if present, etc. All log messages produced by FreeMarker are logged into the logger hierarchy whose top-level logger is named freemarker. Currently used loggers are: Logger name Purpose freemarker.beans Logs messages of the Beans wrapper module. freemarker.cache Logs messages related to template loading and caching. freemarker.runtime Logs template exceptions thrown during template processing. freemarker.runtime.attempt Logs template exceptions thrown during template processing, but caught by attempt/recover directives. Enable DEBUG severity to see the exceptions. freemarker.servlet Logs messages of the FreemarkerServlet class. freemarker.jsp Logs messages of the FreeMarker JSP support. You can call the static selectLoggerLibrary method on the freemarker.log.Logger class and pass it a string that will be used to prefix the above mentioned logger names. This is useful if you want to have separate loggers on a per-web-application basis (assuming the application uses its own local freemarker.jar). Also, you can disable logging with Logger.selectLoggerLibrary(Logger.LIBRARY_NONE). In any case, selectLoggerLibrary must be called early, before FreeMarker could log anything, or else it will not have (consistent) effect.
Using FreeMarker with servlets Servlet HTTP JSP Model 2 Struts Web application framework In a fundamental sense, using FreeMarker in the web application space is no different from anywhere else; FreeMarker writes its output to a Writer that you pass to the Template.process method, and it does not care if that Writer prints to the console or to a file or to the output stream of HttpServletResponse. FreeMarker knows nothing about servlets and Web; it just merges Java object with template files and generates text output from them. From here, it is up to you how to build a Web application around this. But, probably you want to use FreeMarker with some already existing Web application framework. Many frameworks rely on the ``Model 2'' architecture, where JSP pages handle presentation. If you use such a framework (for example, Apache Struts), then read on. For other frameworks please refer to the documentation of the framework.
Using FreeMarker for ``Model 2'' Many frameworks follow the strategy that the HTTP request is dispatched to user-defined ``action'' classes that put data into ServletContext, HttpSession and HttpServletRequest objects as attributes, and then the request is forwarded by the framework to a JSP page (the view) that will generate the HTML page using the data sent with the attributes. This is often referred as Model 2. With these frameworks you can simply use FTL files instead of JSP files. But, since your servlet container (Web application server), unlike with JSP files, does not know out-of-the-box what to do with FTL files, a little extra configuring is needed for your Web application: Copy freemarker.jar (from the lib directory of the FreeMarker distribution) into the WEB-INF/lib directory of your Web application. Insert the following section to the WEB-INF/web.xml file of your Web application (and adjust it if required): <servlet> <servlet-name>freemarker</servlet-name> <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class> <!-- FreemarkerServlet settings: --> <init-param> <param-name>TemplatePath</param-name> <param-value>/</param-value> </init-param> <init-param> <param-name>NoCache</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>ContentType</param-name> <param-value>text/html; charset=UTF-8</param-value> <!-- Forces UTF-8 output encoding! --> </init-param> <!-- FreeMarker settings: --> <init-param> <param-name>template_update_delay</param-name> <param-value>0</param-value> <!-- 0 is for development only! Use higher value otherwise. --> </init-param> <init-param> <param-name>default_encoding</param-name> <param-value>ISO-8859-1</param-value> <!-- The encoding of the template files. --> </init-param> <init-param> <param-name>number_format</param-name> <param-value>0.##########</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>freemarker</servlet-name> <url-pattern>*.ftl</url-pattern> </servlet-mapping> ... <!-- Prevent the visiting of MVC Views from outside the servlet container. RequestDispatcher.forward/include should and will still work. Removing this may open security holes! --> <security-constraint> <web-resource-collection> <web-resource-name>FreeMarker MVC Views</web-resource-name> <url-pattern>*.ftl</url-pattern> </web-resource-collection> <auth-constraint> <!-- Nobody is allowed to visit these --> </auth-constraint> </security-constraint> After this, you can use FTL files (*.ftl) in the same manner as JSP (*.jsp) files. (Of course you can choose another extension besides ftl; it is just the convention) How does it work? Let's examine how JSP-s work. Many servlet container handles JSP-s with a servlet that is mapped to the *.jsp request URL pattern. That servlet will receive all requests where the request URL ends with .jsp, find the JSP file based on the request URL, and internally compiles it to a Servlet, and then call the generated servlet to generate the page. The FreemarkerServlet mapped here to the *.ftl URL pattern does the same, except that FTL files are not compiled to Servlet-s, but to Template objects, and then the process method of Template will be called to generate the page. For example, instead of this JSP file (note that it heavily uses Struts tag-libs to save designers from embedded Java monsters): <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <html> <head><title>Acmee Products International</title> <body> <h1>Hello <bean:write name="user"/>!</h1> <p>These are our latest offers: <ul> <logic:iterate name="latestProducts" id="prod"> <li><bean:write name="prod" property="name"/> for <bean:write name="prod" property="price"/> Credits. </logic:iterate> </ul> </body> </html> you can use this FTL file (use ftl file extension instead of jsp): <html> <head><title>Acmee Products International</title> <body> <h1>Hello ${user}!</h1> <p>These are our latest offers: <ul> <#list latestProducts as prod> <li>${prod.name} for ${prod.price} Credits. </#list> </ul> </body> </html> In FreeMarker <html:form action="/query">...</html:form> is just static text, so it is printed to the output as is, like any other XML or HTML markup. JSP tags are just FreeMarker directives, nothing special, so you use FreeMarker syntax for calling them, not JSP syntax: <@html.form action="/query">...</@html.form>. Note that in the FreeMarker syntax you don't use ${...} in parameters as in JSP, and you don't quote the parameter values. So this is WRONG: <#-- WRONG: --> <@my.jspTag color="${aVariable}" name="aStringLiteral" width="100" height=${a+b} /> and this is good: <#-- Good: --> <@my.jspTag color=aVariable name="aStringLiteral" width=100 height=a+b /> In both templates, when you refer to user and latestProduct, it will first try to find a variable with that name that was created in the template (like prod; if you master JSP: a page scope attribute). If that fails, it will try to look up an attribute with that name in the HttpServletRequest, and if it is not there then in the HttpSession, and if it still doesn't find it then in the ServletContext. In the case of FTL this works because FreemarkerServlet builds the data-model from the attributes of the mentioned 3 objects. That is, in this case the root hash is not a java.util.Map (as it was in some example codes in this manual), but ServletContext+HttpSession+HttpServletRequest; FreeMarker is pretty flexible about what the data-model is. So if you want to put variable "name" into the data-model, then you call servletRequest.setAttribute("name", "Fred"); this is the logic of Model 2, and FreeMarker adapts itself to it. FreemarkerServlet also puts 3 hashes into the data-model, by which you can access the attributes of the 3 objects directly. The hash variables are: Request, Session, Application (corresponds to ServletContext). It also exposes another hash named RequestParameters that provides access to the parameters of the HTTP request. FreemarkerServlet has various init-params. It can be set up to load templates from an arbitrary directory, from the classpath, or relative to the Web application directory. You can set the charset used for templates. You can set up what object wrapper do you want to use. Etc. FreemarkerServlet is easily tailored to special needs through subclassing. Say, if you need to have additional variables available in your data-model for all templates, subclass the servlet and override the preTemplateProcess() method to shove any additional data you need into the model before the template gets processed. Or subclass the servlet, and set these globally available variables as shared variables in the Configuration. For more information please read the Java API documentation of the class.
Including content from other web application resources include servlet include JSP servlet include JSP include You can use the <@include_page path="..."/> custom directive provided by the FreemarkerServlet (since 2.3.15) to include the contents of another web application resource into the output; this is often useful to integrate output of JSP pages (living alongside the FreeMarker templates in the same web server) into the FreeMarker template output. Using: <@include_page path="path/to/some.jsp"/> is identical to using this tag in JSP: <jsp:include page="path/to/some.jsp"> <@include_page ...> is not to be confused with <#include ...>, as the last is for including FreeMarker templates without involving the Servlet container. An <#include ...>-ed template shares the template processing state with the including template, such as the data-model and the template-language variables, while <@include_page ...> starts an independent HTTP request processing. Some Web Application Frameworks provide their own solution for this, in which case you possibly should use that instead. Also some Web Application Frameworks don't use FreemarkerServlet, so include_page is not available. The path can be relative or absolute. Relative paths are interpreted relative to the URL of the current HTTP request (one that triggered the template processing), while absolute paths are absolute in the current servlet context (current web application). You can not include pages from outside the current web application. Note that you can include any page, not just a JSP page; we just used page with path ending in .jsp as an illustration. In addition to the path parameter, you can also specify an optional parameter named inherit_params with a boolean value (defaults to true when not specified) that specifies whether the included page will see the HTTP request parameters of the current request or not. Finally, you can specify an optional parameter named params that specifies new request parameters that the included page will see. In case inherited parameters are passed too, the values of specified parameters will get prepended to the values of inherited parameters of the same name. The value of params must be a hash, with each value in it being either a string, or a sequence of strings (if you need multivalued parameters). Here's a full example: <@include_page path="path/to/some.jsp" inherit_params=true params={"foo": "99", "bar": ["a", "b"]}/> This will include the page path/to/some.jsp, pass it all request parameters of the current request, except for "foo" and "bar", which will be set to "99" and multi-value of "a", "b", respectively. In case the original request already had values for these parameters, the new values will be prepended to the existing values. I.e. if "foo" had values "111" and "123", then it will now have values "99", "111", "123". It is in fact possible to pass non-string values for parameter values within params. Such a value will be converted to a suitable Java object first (i.e. a Number, a Boolean, a Date, etc.), and then its Java toString() method will be used to obtain the string value. It is better to not rely on this mechanism, though, and instead explicitly ensure that parameter values that aren't strings are converted to strings on the template level where you have control over formatting using the ?string and ?c built-ins.
Using JSP custom tags in FTL JSP taglib custom tags taglib FreemarkerServlet puts a hash JspTaglibs into the data-model, what you can use to access JSP taglibs. The JSP custom tags will be accessible as plain user-defined directives. For example, this is a JSP file that uses some Struts tags: <%@page contentType="text/html;charset=ISO-8859-2" language="java"%> <%@taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> <html> <body> <h1><bean:message key="welcome.title"/></h1> <html:errors/> <html:form action="/query"> Keyword: <html:text property="keyword"/><br> Exclude: <html:text property="exclude"/><br> <html:submit value="Send"/> </html:form> </body> </html> And this is the (near) equivalent FTL: <#assign html=JspTaglibs["/WEB-INF/struts-html.tld"]> <#assign bean=JspTaglibs["/WEB-INF/struts-bean.tld"]> <html> <body> <h1><@bean.message key="welcome.title"/></h1> <@html.errors/> <@html.form action="/query"> Keyword: <@html.text property="keyword"/><br> Exclude: <@html.text property="exclude"/><br> <@html.submit value="Send"/> </@html.form> </body> </html> Since JSP custom tags are written to operate in JSP environment, they assume that variables (often referred as ``beans'' in JSP world) are stored in 4 scopes: page scope, request scope, session scope and application scope. FTL has no such notation (the 4 scopes), but FreemarkerServlet provides emulated JSP environment for the custom JSP tags, which maintains correspondence between the ``beans'' of JSP scopes and FTL variables. For the custom JSP tags, the request, session and application scopes are exactly the same as with real JSP: the attributes of the javax.servlet.ServletContext, HttpSession and ServletRequest objects. From the FTL side you see these 3 scopes together as the data-model, as it was explained earlier. The page scope corresponds to the FTL global variables (see the global directive). That is, if you create a variable with the global directive, it will be visible for the custom tags as page scope variable through the emulated JSP environment. Also, if a JSP-tag creates a new page scope variable, the result will be the same as if you create a variable with the global directive. Note that the variables in the data-model are not visible as page-scope attributes for the JSP tags, despite that they are globally visible, since the data-model corresponds to the request, session and application scopes, not the page-scope. On JSP pages you quote all attribute values, it does not mater if the type of the parameter is string or boolean or number. But since custom tags are accessible in FTL templates as user-defined FTL directives, you have to use the FTL syntax rules inside the custom tags, not the JSP rules. So when you specify the value of an ``attribute'', then on the right side of the = there is an FTL expression. Thus, you must not quote boolean and numerical parameter values (e.g. <@tiles.insert page="/layout.ftl" flush=true/>), or they are interpreted as string values, and this will cause a type mismatch error when FreeMarker tries to pass the value to the custom tag that expects non-string value. Also note, that naturally, you can use any FTL expression as attribute value, such as variables, calculated values, etc. (e.g. <@tiles.insert page=layoutName flush=foo && bar/>). FreeMarker does not rely on the JSP support of the servlet container in which it is run when it uses JSP taglibs since it implements its own lightweight JSP runtime environment. There is only one small detail to pay attention to: to enable the FreeMarker JSP runtime environment to dispatch events to JSP taglibs that register event listeners in their TLD files, you should add this to the WEB-INF/web.xml of your Web application: <listener> <listener-class>freemarker.ext.jsp.EventForwarding</listener-class> </listener> Note that you can use JSP taglibs with FreeMarker even if the servlet container has no native JSP support, just make sure that the javax.servlet.jsp.* packages for JSP 1.2 (or later) are available to your Web application. If your servlet container comes with JSP 1.1, then you have to obtain the following six classes (for example you can extract them from the jar-s of Tomcat 5.x or Tomcat 4.x), and copy them into your webapp's WEB-INF/classes/... directory: javax.servlet.jsp.tagext.IterationTag, javax.servlet.jsp.tagext.TryCatchFinally, javax.servlet.ServletContextListener, javax.servlet.ServletContextAttributeListener, javax.servlet.http.HttpSessionAttributeListener, javax.servlet.http.HttpSessionListener. But beware, since containers that come with JSP 1.1 usually use earlier Serlvet versions than 2.3, event listeners will not be supported, and thus JSP 1.2 taglibs that register event listeners will not work properly. As of this writing, JSP features up to JSP 2.1 are implemented, except the "tag files" feature of JSP 2 (i.e., custom JSP tags implemented in JSP language). The tag files had to be compiled to Java classes to be usable under FreeMarker.
Embed FTL into JSP pages JSP taglib There is a taglib that allows you to put FTL fragments into JSP pages. The embedded FTL fragment can access the attributes (Beans) of the 4 JSP scopes. You can find a working example and the taglib in the FreeMarker distribution.
Configuring security policy for FreeMarker security When FreeMarker is used in a Java virtual machine with a security manager installed, you have to grant it few permissions to ensure it operates properly. Most notably, you need these entries to your security policy file for freemarker.jar: grant codeBase "file:/path/to/freemarker.jar" { permission java.util.PropertyPermission "file.encoding", "read"; permission java.util.PropertyPermission "freemarker.*", "read"; } Additionally, if you are loading templates from a directory, you need to give FreeMarker permissions to read files from that directory using the following permission: grant codeBase "file:/path/to/freemarker.jar" { ... permission java.io.FilePermission "/path/to/templates/-", "read"; } Finally, if you're just using the default template loading mechanism which loads templates from the current directory, then specify these permissions additionally: (note that the expression ${user.dir} will be evaluated at run time by the policy interpreter, pretty much as if it were a FreeMarker template) grant codeBase "file:/path/to/freemarker.jar" { ... permission java.util.PropertyPermission "user.dir", "read"; permission java.io.FilePermission "${user.dir}/-", "read"; } Naturally, if you're running under Windows, use double backslash instead of a single slash for separating directory components in paths.
Legacy XML wrapper implementation The legacy XML wrapper is deprecated. FreeMarker 2.3 has introduced support for a new XML processing model. To support this, a new XML wrapper package was introduced, freemarker.ext.dom. For new usage, we encourage you to use that. It is documented in the part . The class freemarker.ext.xml.NodeListModel provides a template model for wrapping XML documents represented as node trees. Every node list can contain zero or more XML nodes (documents, elements, texts, processing instructions, comments, entity references, CDATA sections, etc.). The node list implements the following template model interfaces with the following semantics:
TemplateScalarModel When used as a scalar, the node list will render the XML fragment that represents its contained nodes. This makes it handy for use in XML-to-XML transforming templates.
TemplateCollectionModel When used as a collection with list directive, it will simply enumerate its nodes. Every node will be returned as a new node list consisting of a single node.
TemplateSequenceModel When used as a sequence, it will return the i-th node as a new node list consisting of the single requested node. I.e. to return the 3rd <chapter> element of the <book> element, you'd use the following (note indexes are zero-based): <#assign 3rdChapter = xmldoc.book.chapter[2]>
TemplateHashModel When used as a hash, it is basically used to traverse children. That is, if you have a node list named book that wraps an element node with several chapters, then the book.chapter will yield a node list with all chapter elements of that book element. The at sign is used to refer to attributes: book.@title yields a node list with a single attribute node, that is the title attribute of the book element. It is important to realize the consequence that, for example, if book has no chapter-s then book.chapter is an empty sequence, so xmldoc.book.chapter?? will not be false, it will be always true! Similarly, xmldoc.book.somethingTotallyNonsense?? will not be false either. To check if there was no children found, use xmldoc.book.chapter?size == 0. The hash defines several "magic keys" as well. All these keys start with an underscore. The most notable is the _text key which retrieves the text of the node: ${book.@title._text} will render the value of the attribute into the template. Similarly, _name will retrieve the name of the element or attribute. * or _allChildren returns all direct children elements of all elements in the node list, while @* or _allAttributes returns all attributes of the elements in the node list. There are many more such keys; here's a detailed summary of all the hash keys: Key name Evaluates to * or _children all direct element children of current nodes (non-recursive). Applicable to element and document nodes. @* or _attributes all attributes of current nodes. Applicable to elements only. @attributeName named attributes of current nodes. Applicable to elements, doctypes and processing instructions. On doctypes it supports attributes publicId, systemId and elementName. On processing instructions, it supports attributes target and data, as well as any other attribute name specified in data as name="value" pair. The attribute nodes for doctype and processing instruction are synthetic, and as such have no parent. Note, however that @* does NOT operate on doctypes or processing instructions. _ancestor all ancestors up to root element (recursive) of current nodes. Applicable to same node types as _parent. _ancestorOrSelf all ancestors of current nodes plus current nodes. Applicable to same node types as _parent. _cname the canonical names of current nodes (namespace URI + local name), one string per node (non-recursive). Applicable to elements and attributes _content the complete content of current nodes, including children elements, text, entity references, and processing instructions (non-recursive). Applicable to elements and documents. _descendant all recursive descendant element children of current nodes. Applicable to document and element nodes. _descendantOrSelf all recursive descendant element children of current nodes plus current nodes. Applicable to document and element nodes. _document all documents the current nodes belong to. Applicable to all nodes except text. _doctype doctypes of the current nodes. Applicable to document nodes only. _filterType 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 arbitrary number of strings to this method containing the names of types to keep. Valid type names are: "attribute", "cdata", "comment", "document", "documentType", "element", "entity", "entityReference", "processingInstruction", "text". _name the names of current nodes, one string per node (non-recursive). Applicable to elements and attributes (returns their local names), entities, processing instructions (returns its target), doctypes (returns its public ID) _nsprefix the namespace prefixes of current nodes, one string per node (non-recursive). Applicable to elements and attributes _nsuri the namespace URIs of current nodes, one string per node (non-recursive). Applicable to elements and attributes _parent parent elements of current nodes. Applicable to element, attribute, comment, entity, processing instruction. _qname the qualified names of current nodes in [namespacePrefix:]localName form, one string per node (non-recursive). Applicable to elements and attributes _registerNamespace(prefix, uri) 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 nodelist["prefix:localname"] or nodelist["@prefix:localname"] 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. _text 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 not escaped. _type Returns a node list containing one string per node describing the type of the node. Possible node type names are: "attribute", "cdata", "comment", "document", "documentType", "element", "entity", "entityReference", "processingInstruction", "text". If the type of the node is unknown, returns "unknown". _unique 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 _parent, _ancestor, _ancestorOrSelf, and _document. I.e. foo._children._parent 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 foo._children._parent._unique to eliminate duplicates. Applicable to all node types. any other key element children of current nodes with name matching the key. This allows for convenience child traversal in book.chapter.title style syntax. Note that nodeset.childname is technically equivalent to nodeset("childname"), but is both shorter to write and evaluates faster. Applicable to document and element nodes.
TemplateMethodModel When used as a method model, it returns a node list that is the result of evaluating an XPath expression on the current contents of the node list. For this feature to work, you must have the Jaxen library in your classpath. For example: <#assign firstChapter=xmldoc("//chapter[first()]")>
Namespace handling For purposes of traversal of children elements that have namespace-scoped names, you can register namespace prefixes with the node list. You can do it either in Java, calling the public void registerNamespace(String prefix, String uri); method, or inside a template using the ${nodelist._registerNamespace(prefix, uri)} syntax. From there on, you can refer to children elements in the namespace denoted by the particular URI through the syntax nodelist["prefix:localName"] and nodelist["@prefix:localName"] as well as use these namespace prefixes in XPath expressions. Namespaces registered with a node list are propagated to all node lists that are derived from the original node list. Note also that namespaces are matched by their URI only, so you can safely use a prefix for a namespace inside your template that differs from the prefix in the actual XML document - a prefix is just a local alias for the URI both in the template and in the XML document.
Using FreeMarker with Ant ant task There are two ``FreeMarker Ant tasks'' that we know about: FreemarkerXmlTask: It comes with the FreeMarker distribution, packed into the freemarker.jar. This is a lightweight, easy-to-use Ant task for transforming XML documents with FreeMarker templates. Its approach is that the source files (input files) are XML files, which are rendered to corresponding output files, by a single template. That is, for each XML file, the template will be executed (with the XML document in the data-model), and the template output will be written into a file of similar name than the name of the XML file. Thus, the template file plays a similar role as an XSLT style sheet, but it is FTL, not XSLT. command-line FMPP: It's a more heavyweight, less XML centric, third party Ant task (and standalone command-line tool). Its primary approach is that the source files (input files) are template files that generate the corresponding output files themselves, but it also supports the approach of FreemarkerXmlTask for the source files that are XML-s. Also, it has extra features over the FreemarkerXmlTask. What's its drawback then? As it is more complex and more generalized, it's harder to learn and use it. This section introduces the FreemarkerXmlTask. For more information about FMPP visit its homepage: http://fmpp.sourceforge.net/. In order to use the FreemarkerXmlTask, you must first define the freemarker.ext.ant.FreemarkerXmlTask inside your Ant buildfile, then call the task. Suppose you want to transform several XML documents to HTML using the hypothetical "xml2html.ftl" template, with XML documents being located in the directory "xml" and HTML documents generated into directory "html". You would write something like: <taskdef name="freemarker" classname="freemarker.ext.ant.FreemarkerXmlTask"> <classpath> <pathelement location="freemarker.jar" /> </classpath> </taskdef> <mkdir dir="html" /> <freemarker basedir="xml" destdir="html" includes="**/*.xml" template="xml2html.ftl" /> The task would invoke the template for every XML document. Every document would be parsed into a DOM tree, then wrapped as a FreeMarker node variable. When template processing begins, the special variable, .node, is set to the root node of the XML document. Note that if you are using the legacy (FreeMarker 2.2.x and earlier) XML adapter implementation, that still works, and the root of the XML tree is placed in the data-model as the variable document. That contains an instance of the legacy freemarker.ext.xml.NodeListModel class. Note that all properties defined by the build file would be made available as a hash model named "properties". Several other models are made available; for detailed description of what variables are made available to templates as well as what other attributes can the task accept, see the JavaDoc for freemarker.ext.ant.FreemarkerXmlTask.
Jython wrapper wrapping jython jython wrapping The freemarker.ext.jython package consists of models that enable any Jython object to be used as a TemplateModel. In the very basic case, you only need to call the public TemplateModel wrap(Object obj); method of the freemarker.ext.jython.JythonWrapper class. This method will wrap the passed object into an appropriate TemplateModel. Below is a summary of the properties of returned model wrappers. Let's assume that the model that resulted from the JythonWrapper call on object obj is named model in the template model root for the sake of the following discussion.
TemplateHashModel functionality PyDictionary and PyStringMap will be wrapped into a hash model. Key lookups are mapped to the __finditem__ method; if an item is not found, a model for None is returned.
TemplateScalarModel functionality Every python object will implement TemplateScalarModel whose getAsString() method simply delegates to toString().
TemplateBooleanModel functionality Every python object will implement TemplateBooleanModel whose getAsBoolean() method simply delegates to __nonzero__() in accordance with Python semantics of true/false.
TemplateNumberModel functionality Model wrappers for PyInteger, PyLong, and PyFloat objects implement TemplateNumberModel whose getAsNumber() method returns __tojava__(java.lang.Number.class).
TemplateSequenceModel functionality Model wrappers for all classes that extend PySequence will implement TemplateSequenceModel and thus their elements will be accessible by index using the model[i] syntax, which will delegate to __finditem__(i). You can also query the length of the array or the size of the list using the model?size built-in, which will delegate to __len__().
XML Processing Guide Preface Although FreeMarker was originally designed as a web page template engine, as of version 2.3 it also targets another application domain: transforming XML into arbitrary textual output (e.g. HTML files). Thus, in many cases, FreeMarker is an XSLT alternative. Technically, there is nothing special in transforming XML documents. It's just like when you do anything else with FreeMarker: you drop the XML document into the data-model (and possibly other variables), and then you merge the data-model with the FTL template(s) that generate the output text. The extra features introduced for better XML processing are the node FTL variable type (symbolizes a node in generic tree structures, usable not only for XML) and the built-ins and directives dealing with them, and the XML wrapper you get out-of-the-box that exposes XML documents as FTL variables for the templates. What's the difference between using FreeMarker or XSLT? The FTL language has the usual imperative/procedural logic. On the other hand, XSLT is a language with declarative style, designed by "too clever" people, so it's not easy to adopt its logic, nor to use it in many cases. Also its syntax is terribly verbose. However, XSLT's "apply-templates" method can be very handy when you process XML documents, thus FreeMarker supports something similar called the ``visitor pattern''. So in many applications, it is much easier to write FTL stylesheets than XSLT style-sheets. Another fundamental difference is that FTL "transforms" the node tree to text, while XSLT transforms the tree to another tree. So you cannot always use FreeMarker where you can use XSLT. Exposing XML documents XML exposing
The DOM tree We will use this XML document for the examples: <book> <title>Test Book</title> <chapter> <title>Ch1</title> <para>p1.1</para> <para>p1.2</para> <para>p1.3</para> </chapter> <chapter> <title>Ch2</title> <para>p2.1</para> <para>p2.2</para> </chapter> </book> W3C DOM models an XML document as a tree of nodes. The node tree of the above XML can be visualized as: document | +- element book | +- text "\n " | +- element title | | | +- text "Test Book" | +- text "\n " | +- element chapter | | | +- text "\n " | | | +- element title | | | | | +- text "Ch1" | | | +- text "\n " | | | +- element para | | | | | +- text "p1.1" | | | +- text "\n " | | | +- element para | | | | | +- text "p1.2" | | | +- text "\n " | | | +- element para | | | +- text "p1.3" | +- element | +- text "\n " | +- element title | | | +- text "Ch2" | +- text "\n " | +- element para | | | +- text "p2.1" | +- text "\n " | +- element para | +- text "p2.2" Note that the disturbing "\n  "-s are the line-breaks (indicated here with \n, an escape sequence used in FTL string literals) and the indentation spaces between the tags. Notes on the DOM related terminology: The topmost node of a tree is called the root. In the case of XML documents, it is always the ``document'' node, and not the top-most element (book in this example). We say that node B is the child of node A, if B is the immediate descendant of A. For example, the two chapter element nodes are the children of the book element node, but the para element nodes are not. We say that node A is the parent of node B, if A is the immediate ascendant of node B, that is, if B is the children of A. For example, the book element node is the parent of the two chapter element nodes, but it is not the parent of the para element nodes. There are several kind of components that can occur in XML documents, such as elements, text, comments, processing instructions, etc. All such components are nodes in the DOM tree, so there are element nodes, text nodes, comment nodes, etc. In principle, the attributes of elements are also nodes in the tree -- they are the children of the element --, but still, usually we (and other XML related technologies) exclude them of element children. So basically they don't count as children nodes. The programmer drops the document node of the DOM tree into the FreeMarker data-model, and then the template author can walk the DOM tree using that variable as the starting-point. The DOM nodes in FTL correspond to node variables. This is a variable type, similarly to type string, number, hash, etc. Node variable type makes it possible for FreeMarker to get the parent node and the child nodes of a node. This is technically required to allow the template author to navigate between the nodes, say, to use the node built-ins or the visit and recurse directives; we will show the usage of these in the further chapters.
Putting the XML into the data-model This section is for programmers. It's easy to create a simple program to try the examples. Just replace the ``Create a data-model'' part of the example of Programmer's Guide Quickstart with this: /* Create a data-model */ Map root = new HashMap(); root.put( "doc", freemarker.ext.dom.NodeModel.parse(new File("the/path/of/the.xml"))); and then you have a program that outputs the result of the XML transformation to the standard output (usually the terminal screen). Notes: The parse method removes comment and processing instruction nodes by default. See the API for more details. NodeModel also allows you to wrap org.w3c.dom.Node-s directly. You may want to clean up the DOM tree first with the static utility methods, such as NodeModel.simplify or your own custom cleanup routines. Note that there are tools available that you can use to generate files from XML documents, so you don't have to write your own for this common task. See here...
Imperative XML processing XML imperative processing
Learning by example This section uses the DOM tree and the variable made in the previous chapter. Assume that the programmer has put the XML document into the data-model as variable doc. This variable corresponds to the root of the DOM tree, the ``document''. The actual variable structure behind doc is wily enough, and only roughly resembles the DOM tree. So instead of getting lost in the details, let's see how to use it by example.
Accessing elements by name This FTL prints the title of the book: <h1>${doc.book.title}</h1> The output will be: <h1>Test Book</h1> As you see, both doc and book can be used as hashes; you get their child nodes as subvariables. Basically, you describe the path by which you reach the target (element title) in the DOM tree. You may notice that there was some swindle above: with ${doc.book.title}, it seems that we instruct FreeMarker to print the title element itself, but we should print its child text node (check the DOM tree). It still works, because elements are not only hash variables, but string variables as well. The scalar value of an element node is the string resulting from the concatenation of all its text child nodes. However, trying to use an element as scalar will cause error if the element has child elements. For example ${doc.book} would stop with error. This FTL prints the titles of the two chapters: <h2>${doc.book.chapter[0].title}</h2> <h2>${doc.book.chapter[1].title}</h2> Here, as book has 2 chapter element children, doc.book.chapter is a sequence that stores the two element nodes. Thus, we can generalize the above FTL, so it works with any number of chapters: <#list doc.book.chapter as ch> <h2>${ch.title}</h2> </#list> But what's if there is only one chapter? Actually, when you access an element as hash subvariable, it is always a sequence as well (not only hash and string), but if the sequence contains exactly 1 item, then the variable also acts as that item itself. So, returning to the first example, this would print the book title as well: <h1>${doc.book[0].title[0]}</h1> But you know that there is exactly 1 book element, and that a book has exactly 1 title, so you can omit the [0]-s. ${doc.book.chapter.title} would work too, if the book happen to have only 1 chapter-s (otherwise it is ambiguous: how is it to know if the title of which chapter you want? So it stops with an error.). But since a book can have multiple chapters, you don't use this form. If the element book has no chapter child, then doc.book.chapter will be a 0 length sequence, so the FTL with <#list ...> will still work. It is important to realize the consequence that, for example, if book has no chapter-s then book.chapter is an empty sequence, so doc.book.chapter?? will not be false, it will be always true! Similarly, doc.book.somethingTotallyNonsense?? will not be false either. To check if there was no children found, use doc.book.chapter[0]?? (or doc.book.chapter?size == 0). Of course you can use similarly all the missing value handler operators (e.g. doc.book.author[0]!"Anonymous"), just don't forget that [0]. The rule with sequences of size 1 is a convenience feature of the XML wrapper (implemented via multi-type FTL variables). It will not work with other sequences in general. Now we finish the example by printing all the para-s of each chapter: <h1>${doc.book.title}</h1> <#list doc.book.chapter as ch> <h2>${ch.title}</h2> <#list ch.para as p> <p>${p} </#list> </#list> this will print: <h1>Test</h1> <h2>Ch1</h2> <p>p1.1 <p>p1.2 <p>p1.3 <h2>Ch2</h2> <p>p2.1 <p>p2.2 The above FTL could be written more nicely as: <#assign book = doc.book> <h1>${book.title}</h1> <#list book.chapter as ch> <h2>${ch.title}</h2> <#list ch.para as p> <p>${p} </#list> </#list> Finally, a ``generalized`` usage of the child selector mechanism: this template lists all para-s of the example XML document: <#list doc.book.chapter.para as p> <p>${p} </#list> The output will be: <p>p1.1 <p>p1.2 <p>p1.3 <p>p2.1 <p>p2.2 This example shows that hash subvariables select the children of a sequence of notes (just in the earlier examples that sequence happened to be of size 1). In this concrete case, subvariable chapter returns a sequence of size 2 (since there are two chapter-s), and then subvariable para selects the para child nodes of all nodes in that sequence. A negative consequence of this mechanism is that things like doc.somethingNonsense.otherNonsesne.totalNonsense will just evaluate to an empty sequence, and you don't get any error messages.
Accessing attributes This XML is the same as the original, except that it uses attributes for the titles, instead of elements: <!-- THIS XML IS USED FOR THE "Accessing attributes" CHAPTER ONLY! --> <!-- Outside this chapter examples use the XML from earlier. --> <book title="Test"> <chapter title="Ch1"> <para>p1.1</para> <para>p1.2</para> <para>p1.3</para> </chapter> <chapter title="Ch2"> <para>p2.1</para> <para>p2.2</para> </chapter> </book> The attributes of an element can be accessed in the same way as the child elements of the element, except that you put an at-sign (@) before the name of the attribute: <#assign book = doc.book> <h1>${book.@title}</h1> <#list book.chapter as ch> <h2>${ch.@title}</h2> <#list ch.para as p> <p>${p} </#list> </#list> This will print exactly the same as the previous example. Getting attributes follows the same logic as getting child elements, so the result of ch.@title above is a sequence of size 1. If there were no title attribute, then the result would be a sequence of size 0. So be ware, using existence built-ins is tricky here too: if you are curious if foo has attribute bar then you have to write foo.@bar[0]??. (foo.@bar?? is wrong, because it always returns true.) Similarly, if you want a default value for the bar attribute, then you have to write foo.@bar[0]!"theDefaultValue". As with child elements, you can select the attributes of multiple nodes. For example, this template prints the titles of all chapters: <#list doc.book.chapter.@title as t> ${t} </#list>
Exploring the tree This FTL will enumerate all child nodes of the book element: <#list doc.book?children as c> - ${c?node_type} <#if c?node_type = 'element'>${c?node_name}</#if> </#list> this will print: - text - element title - text - element chapter - text - element chapter - text The meaning of ?node_type is probably clear without explanation. There are several node types that can occur in a DOM tree, such as "element", "text", "comment", "pi", ...etc. The ?node_name returns the name of element for element nodes. For other node types, it also returns something, but that's mainly useful for declarative XML processing, which will be discussed in a later chapter. If the book element had attributes, they would not appear in the above list, for practical reasons. But you can get a list that contains all attributes of the element, with subvariable @@ of the element variable. If you modify the first line of the XML to this: <book foo="Foo" bar="Bar" baaz="Baaz"> and run this FTL: <#list doc.book.@@ as attr> - ${attr?node_name} = ${attr} </#list> then you get this output (or something similar): - baaz = Baaz - bar = Bar - foo = Foo Returning to the listing of children, there is a convenience subvariable to list only the element children of an element: <#list doc.book.* as c> - ${c?node_name} </#list> This will print: - title - chapter - chapter You get the parent of an element with the parent built-in: <#assign e = doc.book.chapter[0].para[0]> <#-- Now e is the first para of the first chapter --> ${e?node_name} ${e?parent?node_name} ${e?parent?parent?node_name} ${e?parent?parent?parent?node_name} This will print: para chapter book @document In the last line you have reached the root of the DOM tree, the document node. It's not an element, and this is why it has that strange name; don't deal with it now. Obviously, the document node has no parent. You can quickly go back to the document node using the root built-in: <#assign e = doc.book.chapter[0].para[0]> ${e?root?node_name} ${e?root.book.title} This will print: @document Test Book For the complete list of built-ins you can use to navigate in the DOM tree, read the reference of node built-ins.
Using XPath expressions XPath expressions work only if Jaxen (recommended, but use at least Jaxen 1.1-beta-8, not older) or Apache Xalan classes are available. (Apache Xalan classes are included in Sun J2SE 1.4, 1.5 and 1.6 (and maybe later too); no separate Xalan jar is needed.) If a hash key used with a node variable can't be interpreted otherwise (see the next section for the precise definition), then it will by interpreted as an XPath expression. For more information on XPath, please visit http://www.w3.org/TR/xpath. For example, here we list the para elements of the chapter with title ``Ch1'': <#list doc["book/chapter[title='Ch1']/para"] as p> <p>${p} </#list> It will print: <p>p1.1 <p>p1.2 <p>p1.3 The rule with sequences of length 1 (explained in earlier sections) stands for XPath results as well. That is, if the resulting sequence contains exactly 1 node, it also acts as the node itself. For example, print the first paragraph of chapter ``Ch1'': ${doc["book/chapter[title='Ch1']/para[1]"]} which prints the same as: ${doc["book/chapter[title='Ch1']/para[1]"][0]} The context node of the XPath expression is the node (or sequence of nodes) whose hash subvariable is used to issue the XPath expression. Thus, this prints the same as the previous example: ${doc.book["chapter[title='Ch1']/para[1]"]} Note that currently you can use a sequence of 0 or multiple (more than 1) nodes as context only if the programmer has set up FreeMarker to use Jaxen instead of Xalan. Also note that XPath indexes sequence items from 1, while FTL indexes sequence items from 0. Thus, to select the first chapter, the XPath expression is "/book/chapter[1]", while the FTL expression is book.chapter[0]. If the programmer has set up FreeMarker to use Jaxen instead of Xalan, then FreeMarker variables are visible with XPath variable references: <#assign currentTitle = "Ch1"> <#list doc["book/chapter[title=$currentTitle]/para"] as p> ... Note that $currentTitle is not a FreeMarker interpolation, as there are no { and } there. That's an XPath expression. The result of some XPath expressions is not a node-set, but a string, a number, or a boolean. For those XPath expressions, the result is an FTL string, number, or boolean variable respectively. For example, the following will count the total number of para elements in the XML document, so the result is a number: ${x["count(//para)"]} The output will be: 5
XML namespaces XML namespace in imperative processing Be default, when you write something like doc.book, then it will select the element with name book that does not belongs to any XML namespace (similarly to XPath). If you want to select an element that is inside an XML namespace, you must register a prefix and use that. For example, if element book is in XML namespace http://example.com/ebook, then you have to associate a prefix with it at the top of the template with the ns_prefixes parameter of the ftl directive: <#ftl ns_prefixes={"e":"http://example.com/ebook"}> And now you can write expressions as doc["e:book"]. (The usage of square bracket syntax was required because the colon would confuse FreeMarker otherwise.) As the value of ns_prefixes is a hash, you can register multiple prefixes: <#ftl ns_prefixes={ "e":"http://example.com/ebook", "f":"http://example.com/form", "vg":"http://example.com/vectorGraphics"} > The ns_prefixes parameter affects the whole FTL namespace. This means in practice that the prefixes you have registered in the main page template will be visible in all <#include ...>-d templates, but not in <#imported ...>-d templates (often referred as FTL libraries). Or from another point of view, an FTL library can register XML namespace prefixes for it's own use, without interfering with the prefix registrations of the main template and other libraries. Note that, if an input document is dominated by a given XML namespace, you can set that as the default namespace for convenience. This means that if you don't use prefix, as in doc.book, then it selects element that belongs to the default namespace. The setting of the default namespace happens with reserved prefix D, for example: <#ftl ns_prefixes={"D":"http://example.com/ebook"}> Now expression doc.book select the book element that belongs to XML namespace http://example.com/ebook. Unfortunately, XPath does not support this idea of a default namespace. Thus, in XPath expressions, element names without prefixes always select the elements that does not belong to any XML namespace. However, to access elements in the default namespace you can directly use prefix D, for example: doc["D:book/D:chapter[title='Ch1']"]. Note that when you use a default namespace, then you can select elements that does not belong to any node namespace with reserved prefix N, for example doc.book["N:foo"]. It doesn't go for XPath expressions, where the above can be witten as doc["D:book/foo"].
Don't forget escaping! We have made a big mistake in all examples. We generate output of HTML format, and HTML format reserves characters as <, &, etc. So when we print plain text (as the titles and paragraphs), we have to escape it. Thus, the correct version of the example is: <#escape x as x?html> <#assign book = doc.book> <h1>${book.title}</h1> <#list book.chapter as ch> <h2>${ch.title}</h2> <#list ch.para as p> <p>${p} </#list> </#list> </#escape> So if the book title is "Romeo & Julia", the resulting HTML output will be correctly: ... <h1>Romeo &amp; Julia</h1> ...
Formal description Every variable that corresponds to a single node in the DOM tree is a multi-type variable of type node and type hash (for programmers: implements both TemplateNodeModel and TemplateHashModel). Thus, you can use the node built-ins with them. Hash keys are interpreted as XPath expressions, except the special keys shown in the table below. Some of the node variables also have string type, so you can use them as string variables (for programmers: they implement TemplateScalarModel). Node type (?node_type) Node name (?node_name) String value (e.g. <p>${node}) Special hash keys "document" "@document" No string value. (Error when you try to use it as string.) "elementName", "prefix:elementName", "*", "**", "@@markup", "@@nested_markup", "@@text" "element" "name": the name of the element. This is the local name (i.e. name without namespace prefix). If it has no element children, the text of all text node children concatenated together. Error otherwise, when you try to use it as string. "elementName", "prefix:elementName", "*", "**", "@attrName", "@prefix:attrName", "@@", "@*", "@@start_tag", "@@end_tag", "@@attributes_markup", "@@markup", "@@nested_markup", "@@text", "@@qname" "text" "@text" The text itself. "@@markup", "@@nested_markup", "@@text" "pi" "@pi$target" The part between the target name and the ?>. "@@markup", "@@nested_markup", "@@text" "comment" "@comment" The text of the comment, without the delimiters <!-- and -->. "@@markup", "@@nested_markup", "@@text" "attribute" "name": the name of the attribute. This is the local name (i.e. name without namespace prefix). The value of the attribute. "@@markup", "@@nested_markup", "@@text", "@@qname" "document_type" "@document_type$name": name is the name of the document element. No string value. (Error when you try to use it as string.) "@@markup", "@@nested_markup", "@@text" Notes: There is no CDATA type. CDATA nodes are transparently considered as text nodes. Variables do not support ?keys and ?values. Element and attribute node names are local names, that is, they do not contain the namespace prefix. The URI of the namespace the node belongs to can be queried with the ?node_namespace built-in. XPath expression needs Jaxen (recommended, but please use 1.1-beta-8 or later; download it here) or Apache Xalan classes available, or an error will stop template execution. Note, however, that as some special hash keys hide the XPath expressions of the same meaning, those XPath expressions will work even if there is no XPath implementation available. If both Xalan and Jaxen is available, FreeMarker will use Xalan, unless you choose Jaxen by calling freemarker.ext.dom.NodeModel.useJaxenXPathSupport() from Java. If Jaxen is used for the XPath support (not Xalan), then FreeMarker variables are visible with XPath variable references (e.g. doc["book/chapter[title=$currentTitle]"]). Meaning of special hash keys: "elementName", "prefix:elementName": Returns the sequence of child nodes that are elements of name elementName. (Note that the term ``child'' means immediate descendant.) The selection is XML name-space aware, unless the XML document was persed with an XML parser that was not in namespace aware mode. In XML name-space aware mode, names without prefix (elementName) selects only elements that doesn't belong to any XML name-space (unless you have registered a default XML namespace), and names with prefix (prefix:elementName) selects only elements that are belonging to the XML namespace denoted by the prefix. The registration of prefixes and the setting of the default XML namespace is done with the ns_prefixes parameter of the ftl directive. "*": Returns the sequence of all child (direct descedant) element nodes. The sequence will contain the elements in the ``document order'', that is, in the order in which the first character of the XML representation of each node occurs (after expansion of general entities). "**": Returns the sequence of all descendant element nodes. The sequence will contain the elements in the document order. "@attName", "@prefix:attrName": Returns the attribute attName of the element as a sequence of size 1 that contains the attribute node, or as an empty sequence if the attribute does not exist (so to check if an attribute exists use foo.@attName[0]??, not foo.@attName??). As with special key "elementName", if the length of the sequence is 1, then it also acts as its first subvariable. If no prefix is used, then it returns only attribute that does not use XML namespace (even if you have set a default XML namespace). If a prefix is used, it returns only the attribute that belongs to the XML namespace associated with the prefix. The registration of prefixes is done with the ns_prefixes parameter of the ftl directive. "@@" or "@*": Returns the sequence of attribute nodes belonging to the parent element. This is the same as XPath @*. "@@qname": Returns the full-qualified name of the element (such as e:book, in contrast to the local name returned by ?node_name that is book) . The prefix used (as e) is chosen based on the prefix registered in the current namespace with the ns_prefixes parameter of the ftl directive, and not influenced by the prefix used in the source XML document. If you have set a default XML namespace, then for nodes that use that, prefix D will be used. For nodes that does not belong to an XML namespace, no prefix is used (even if you have set a default namespace). If there is no prefix registered for the namespace of the node, the result is a non-existent variable (node.@@qname?? is false). "@@markup": This returns the full XML markup of a node, as a string. (Full XML markup means that it also contains the markup of the child nodes, and the markup of the children of the child nodes, and so on.) The markup you get is not necessary the same as the markup in the source XML file, it's just semantically identical. Especially, note that CDATA sections will become to plain text. Also note that depending on how did you wrapped the original XML document with FreeMarker, comment or processing instruction nodes may were removed, and then they will be missing from the output of course. The first outputted start tag will contain xmlns:prefix attributes for each XML name-spaces used in the outputted XML fragment, and those prefixes will be used in the outputted element and attribute names. These prefixes will be the same as the prefixes registered with the ns_prefixes parameter of the ftl directive (no prefix will be used for D, as it will be registered as the default name-space with an xmlns attribute), or if no prefix was assigned for a XML name-space with that, then an arbitrary chosen unused prefix is used. "@@nested_markup": This is similar to "@@markup", but it returns the XML markup of an element without its opening and closing tags. For the document node, it returns the same as "@@markup". For other node types (text, processing instruction, etc.), it returns an empty string. Unlike with "@@markup", no xmlns:prefix attributes will be placed into the ouput, but regarding the prefixes used in element and attribute names the rules are the same. "@@text": This returns the value of all text nodes that occur within the node (all descendant text nodes, not just direct children), concatenated together into a single string. If the node has no text node children, then the result is an empty string. "@@start_tag": Returns the markup of the start-tag of the element node. As with @@markup, the output is not necessary the same as in the original XML document, but it is semantically equivalent with that. Regarding the XML name-spaces (xmlns:prefix attributes in the output, etc.) the rules are the same as with "@@markup" "@@end_tag": Returns the markup of the end-tag of the element node. As with @@markup, the output is not necessary the same as in the original XML document, but it is semantically equivalent with that. @@attributes_markup: Returns the markup of the attributes of the element node. As with @@markup, the output is not necessary the same as in the original XML document, but it is semantically equivalent with that.
Node sequences Many of the special hash keys (indicated in the above list), and XPath expressions that result in node-sets (see the XPath recommendation) return a sequence of nodes. These node sequences, if they store exactly 1 subvariable, will also act as the subvariable itself. For example, ${book.title[0]} will do the same as ${book.title}, if there is only one title element child of element book. Returning an empty node sequence is a normal situation. For example, if in a concrete XML document, element book has no child element chapter, then book.chapter results in an empty node sequence. Beware! This also means, that book.chaptre (note the typo) will also return empty node sequence, and will not stop with error. Also, book.chaptre?? (note the typo) will return true because the empty sequence exists, so you have to use book.chaptre[0]?? for the check. Node sequences that store not 1 nodes (but 0 or more than 1 nodes) also support some of the hash keys described above. Namely, the following special keys are supported: "elementName", "prefix:elementName" "@attrName", "@prefix:attrName" "@@markup", "@@nested_markup" "@@text" "*", "**" "@@", "@*" When you apply one of the above special keys on a node sequence that contains more than 1 or 0 nodes, then for each node in the sequence (where the special key does make sense, e.g. text nodes will be skipped for key * or @foo), the special key will be applied as it was explained for single nodes, and the results will be concatenated to form the final result. The results will be concatenated in the order as the corresponding nodes occur in the node sequence. The concatenation means string or sequence concatenation depending on the type of the results. If the special key would result in a string for a single node, then for multiple nodes the result is a single string too (the results for the single nodes concatenated), and if the special key would return a sequence for a single node, then for multiple nodes the result is a single sequence too. If there are 0 nodes in the sequence you apply the special key on, the string result is an empty string or an empty sequence respectively. XPath expressions can be used with node sequences. However, for 0 or more than 1 nodes it will work only if you use Jaxen instead of Xalan, because of the limitations of the Xalan XPath implementation.
Declarative XML Processing XML declarative processing XSLT
Basics This section uses the DOM tree and the variable made in a previous chapter. With the imperative approach of XML processing -- this was shown in the previous chapter -- you write an FTL program that walks the tree to find the different kind of nodes. With the declarative approach, you rather define how to handle the different kind of nodes, and then let FreeMarker walk the tree an call the handlers you have defined. This approach is useful for complex XML schemas, where the same element can occur as the child of many other elements. Examples of such schemas are XHTML and XDocBook. The directive you most often use with the declarative approach is the recurse directive. This directive gets a node variable as parameter, and ``visits'' all its children nodes, one after the other, starting with the first child. ``Visiting'' a node means that it calls a user-defined directive (like a macro) that has the same name as the name of the child node (?node_name). We say on this, that the user-defined directive handles the node. The node that the user-defined directive just handles is available as special variable .node. For example, this FTL: <#recurse doc> <#macro book> I'm the book element handler, and the title is: ${.node.title} </#macro> will print (I have removed some disturbing white-space form the output): I'm the book element handler, and the title is: Test Book If you call recurse without parameter, then it uses .node, that is, it visits all children nodes of the node being handled currently. So this FTL: <#recurse doc> <#macro book> Book element with title ${.node.title} <#recurse> End book </#macro> <#macro title> Title element </#macro> <#macro chapter> Chapter element with title: ${.node.title} </#macro> will print (I have removed disturbing white-space form the output): Book element with title Test Book Title element Chapter element with title: Ch1 Chapter element with title: Ch2 End book You have seen how to define handlers for element nodes, but not how to define handler for the text nodes. Since the name of the handler is the same as the node-name of nodes it handles, and as the node-name of all text nodes is @text (see the table), you define handler for the text nodes like this: <#macro @text>${.node?html}</#macro> Note the ?html. You have to HTML-escape the text, since you generate output of HTML format. Here it is the template that transforms the XML to complete HTML: <#recurse doc> <#macro book> <html> <head> <title><#recurse .node.title></title> </head> <body> <h1><#recurse .node.title></h1> <#recurse> </body> </html> </#macro> <#macro chapter> <h2><#recurse .node.title></h2> <#recurse> </#macro> <#macro para> <p><#recurse> </#macro> <#macro title> <#-- We have handled this element imperatively, so we do nothing here. --> </#macro> <#macro @text>${.node?html}</#macro> and the output will be (now I will honestly include the annoying white-space...): <html> <head> <title>Test Book</title> </head> <body> <h1>Test Book</h1> <h2>Ch1</h2> <p>p1.1 <p>p1.2 <p>p1.3 <h2>Ch2</h2> <p>p2.1 <p>p2.2 </body> </html> Note that you can reduce substantially the amount of superfluous whitespace in the output by using the trim directives, as <#t>. See also: You may say that the FTL that did it with imperative approach was much shorter. That's true, but the example XML uses a very simple schema, and as I said, the declarative approach brings its form with XML schemas that are not that firm about what element can occur where. Say, introduce element mark, that should color text to red, does not mater where do you use it; in a title, or in a para. For this, with the declarative approach, you just add a macro: <#macro mark><font color=red><#recurse></font></#macro> And then <mark>...</mark> will automatically work everywhere. So for certain XML schemas, declarative XML processing will actually result in shorter, and what is even more important, much clearer FTL-s, than imperative XML processing. It's up to you to decide which approach to use when; don't forget that you can mix the two approaches freely. Say, in an element handler, you can use imperative approach to process the contents of that element.
Details
Default handlers For some XML node types, there is a default handler, which will handle the node if you haven't defined a handler for the node (i.e. if there is no user-defined directive available with name identical to the node name). Here are these node types, and what the default handler does: Text node: prints the text as it. Note, that in most applications, this will not be good for you, because you should escape the text before you send it to the output (with ?html or ?xml or ?rtf, ...etc. depends on the output format). Processing instruction node: call handler called @pi if you have created such user-defined directive, otherwise do nothing (ignore the node). Comment node, document type node: Do nothing (ignore the node). Document node: Call recurse, that is, visit all children of the document node. Element and attribute nodes will be handled according to the usual, XML independent mechanism. That is, @node_type will be called as handler, and if that's not defined, then an error stops template processing. In the case of element nodes, this means that if you define a macro (or other kind of user-defined directive) called @element, that will catch all element nodes, which has no more specific handler. If you have no @element handler, then you must define a handler for all possible elements. Attribute nodes are not visited by the recurse directive, so you don't need to write handlers for them.
Visiting a single node With the visit directive you can visit a single node, instead of the children of the node: <#visit nodeToVisist>. This can be useful sometimes.
XML namespaces XML namespaces in declarative processing We said that the name of the handler user-defined directive (like a macro) for an element is the name of the element. In fact, it is the full-qualified name of the element: prefix:elementName. The rules regarding the usage of prefix-es is the same as with imperative processing. Thus, the user-defined book directive handles only element book that does not belong to any XML namespace (unless you have specified a default XML namespace). So if the example XML would use XML namespace http://example.com/ebook: <book xmlns="http://example.com/ebook"> ... Then the FTL should look as this: <#ftl ns_prefixes={"e":"http://example.com/ebook"}> <#recurse doc> <#macro "e:book"> <html> <head> <title><#recurse .node["e:title"]></title> </head> <body> <h1><#recurse .node["e:title"]></h1> <#recurse> </body> </html> </#macro> <#macro "e:chapter"> <h2><#recurse .node["e:title"]></h2> <#recurse> </#macro> <#macro "e:para"> <p><#recurse> </#macro> <#macro "e:title"> <#-- We have handled this element imperatively, so we do nothing here. --> </#macro> <#macro @text>${.node?html}</#macro> Or, you can define a default XML namespace, and then the further part of the template remains the same as in the original XML namespace free example: <#ftl ns_prefixes={"D":"http://example.com/ebook"}> <#recurse doc> <#macro book> ... But in this case don't forge that in XPath expressions (we didn't used any in the example) the default XML namespace must be accessed with an explicit D: since names without prefix always refer to nodes with no XML namespace in XPath. Also note that with the same logic as with imperative XML processing, the name of handlers for elements that has no XML namespace is N:elementName if (and only if) there is a default XML namespace. However, for nodes that are not of type element (such as text nodes), you never use the N prefix in the handler name, because those nodes are free of the idea of XML namespaces. So for example, the handler for text nodes is always just @text. For more detailed information, please read the reference of recurse and visit directives.
Reference Built-in Reference built-in
Alphabetical index built-in ancestors byte c cap_first capitalize ceiling children chop_linebreak chunk contains date for dates, for strings datetime for dates, for strings double ends_with eval first floor groups float has_content html index_of int interpret is_... iso, iso_... j_string js_string keys last last_index_of left_pad length long lower_case matches namespace new node_namespace node_name node_type number number_to_date, number_to_datetime, number_to_time parent replace reverse right_pad round root rtf short size sort seq_contains seq_index_of seq_last_index_of sort_by split starts_with string: for strings, for numbers, for booleans, for date/times substring time for dates, for strings trim uncap_first upper_case url values word_list xhtml xml If you don't find a built-in here that you have seen in a working template, probably you will find it here:
Built-ins for strings string built-ins
substring substring built-in This built-in exists since FreeMarker 2.3.7. Synopsis: exp?substring(from, toExclusive), also callable as exp?substring(from) A substring of the string. from is the index of the first character. It must be a number that is at least 0 and less than or equal with toExclusive, or else an error will abort the template processing. The toExclusive is the index of the character position after the last character of the substring, or with other words, it is one greater than the index of the last character. It must be a number that is at least 0 and less than or equal to the length of the string, or else an error will abort the template processing. If the toExclusive is omitted, then it defaults to the length of the string. If a parameter is a number that is not an integer, only the integer part of the number will be used. Example: - ${'abc'?substring(0)} - ${'abc'?substring(1)} - ${'abc'?substring(2)} - ${'abc'?substring(3)} - ${'abc'?substring(0, 0)} - ${'abc'?substring(0, 1)} - ${'abc'?substring(0, 2)} - ${'abc'?substring(0, 3)} - ${'abc'?substring(0, 1)} - ${'abc'?substring(1, 2)} - ${'abc'?substring(2, 3)} The output: - abc - bc - c - - - a - ab - abc - a - b - c
cap_first cap_first built-in The string with the very first word of the string capitalized. For the precise meaning of ``word'' see the word_list built-in. Example: ${" green mouse"?cap_first} ${"GreEN mouse"?cap_first} ${"- green mouse"?cap_first} The output: Green mouse GreEN mouse - green mouse In the case of "- green mouse", the first word is the -.
uncap_first uncap_first built-in The opposite of cap_first. The string with the very first word of the string un-capitalized.
capitalize capitalize built-in The string with all words capitalized. For the precise meaning of ``word'' see the word_list built-in. Example: ${" green mouse"?capitalize} ${"GreEN mouse"?capitalize} The output: Green Mouse Green Mouse
chop_linebreak chop_linebreak built-in The string without the line-break at its very end if there was a line-break, otherwise the unchanged string.
date, time, datetime type-casting converting between types date built-in time built-in datetime built-in string to date string to time converting string to date converting string to time parsing string as date parsing string as time The string converted to a date value. It is recommended to specify a parameter that specifies the format. For example: <#assign test1 = "10/25/1995"?date("MM/dd/yyyy")> <#assign test2 = "15:05:30"?time("HH:mm:ss")> <#assign test3 = "1995-10-25 03:05 PM"?datetime("yyyy-MM-dd hh:mm a")> ${test1} ${test2} ${test3} will print something like (depends on the output locale (language) and on other settings): Oct 25, 1995 3:05:30 PM Oct 25, 1995 3:05:00 PM Note that the dates was converted back to string according to the date_format, time_format and datetime_format settings (for more information about converting dates to strings read: string built-in for dates, date interpolations). It does not mater what format did you use when you have converted the strings to dates. You don't have to use the format parameter, if you know what the default date/time/datetime format will be when the template is processed: <#assign test1 = "Oct 25, 1995"?date> <#assign test2 = "3:05:30 PM"?time> <#assign test3 = "Oct 25, 1995 03:05:00 PM"?datetime> ${test1} ${test2} ${test3} If the string is not in the appropriate format, an error will abort template processing when you try to access this built-in.
ends_with ends_with built-in Returns if this string ends with the specified substring. For example "redhead"?ends_with("head") returns boolean true. Also, "head"?ends_with("head") will return true.
html escaping output html built-in The string as HTML markup. That is, the string with all: < replaced with &lt; > replaced with &gt; & replaced with &amp; " replaced with &quot; Note that if you want to insert an attribute value securely, you must quote the attribute value in the HTML template with quotation mark (with ", not with '): <input type=text name=user value="${user?html}"> Note that in HTML pages usually you want to use this built-in for all interpolations. So you can spare a lot of typing and lessen the chances of accidental mistakes by using the escape directive.
groups groups built-in This is used only with the result of the matches built-in. See there...
index_of index_of built-in Returns the index within this string of the first occurrence of the specified substring. For example, "abcabc"?index_of("bc") will return 1 (don't forget that the index of the first character is 0). Also, you can specify the index to start the search from: "abcabc"?index_of("bc", 2) will return 4. There is no restriction on the numerical value of the second parameter: if it is negative, it has the same effect as if it were zero, and if it is greater than the length of this string, it has the same effect as if it were equal to the length of this string. Decimal values will be truncated to integers. If the 1st parameter does not occur as a substring in this string (starting from the given index, if you use the second parameter), then it returns -1.
j_string j_string built-in Escapes the string with the escaping rules of Java language string literals, so it's safe to insert the value into a string literal. Note that it will not add quotation marks around the inserted value; you meant to use this inside the string literal. All characters under UCS code point 0x20 will be escaped. When they have no dedicated escape sequence in the Java language (like \n, \t, etc.), they will be replaced with a UNICODE escape (\uXXXX). Example: <#assign beanName = 'The "foo" bean.'> String BEAN_NAME = "${beanName?j_string}"; will output: String BEAN_NAME = "The \"foo\" bean.";
js_string js_string built-in Escapes the string with the escaping rules of JavaScript language string literals, so it's safe to insert the value into a string literal. Note that it will not add quotation marks around the inserted value; you meant to use this inside the string literal. Both quotation mark (") and apostrophe-quoate (') are escaped. Starting from FreeMarker 2.3.1, it also escapes > as \> (to avoid </script>). All characters under UCS code point 0x20 will be escaped. When they have no dedicated escape sequence in JavaScript (like \n, \t, etc.), they will be replaced with a UNICODE escape (\uXXXX). Example: <#assign user = "Big Joe's \"right hand\""> <script> alert("Welcome ${user?js_string}!"); </script> will output: <script> alert("Welcome Big Joe\'s \"right hand\"!"); </script>
json_string json_string built-in Escapes the string with the escaping rules of JSON language string literals, so it's safe to insert the value into a string literal. Note that it will not add quotation marks around the inserted value; you meant to use this inside the string literal. This will not escape ' characters, since JSON strings must be quoted with ". It will, however escape the / (slash) characters as \/ where they occur directly after a <, to avoid </script> and such. It will also escape the > characters as \u003E where they occur directly after ]], to avoid exiting an XML CDATA section. All characters under UCS code point 0x20 will be escaped. When they have no dedicated escape sequence in JSON (like \n, \t, etc.), they will be replaced with a UNICODE escape (\uXXXX).
last_index_of last_index_of built-in Returns the index within this string of the last (rightmost) occurrence of the specified substring. It returns the index of the first (leftmost) character of the substring. For example: "abcabc"?last_index_of("ab") will return 3. Also, you can specify the index to start the search from. For example, "abcabc"?last_index_of("ab", 2) will return 0. Note that the second parameter indicates the maximum index of the start of the substring. There is no restriction on the numerical value of the second parameter: if it is negative, it has the same effect as if it were zero, and if it is greater than the length of this string, it has the same effect as if it were equal to the length of this string. Decimal values will be truncated to inegers. If the 1st parameter does not occur as a substring in this string (before the given index, if you use the second parameter), then it returns -1.
length length built-in The number of characters in the string.
lower_case lower_case built-in The lower case version of the string. For example "GrEeN MoUsE"?lower_case will be "green mouse".
left_pad left_pad built-in padding This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. If it's used with 1 parameter, then it inserts spaces on the beginning of the string until it reaches the length that is specified as the parameter. If the string is already as long or longer than the specified length, then it does nothing. For example, this: [${""?left_pad(5)}] [${"a"?left_pad(5)}] [${"ab"?left_pad(5)}] [${"abc"?left_pad(5)}] [${"abcd"?left_pad(5)}] [${"abcde"?left_pad(5)}] [${"abcdef"?left_pad(5)}] [${"abcdefg"?left_pad(5)}] [${"abcdefgh"?left_pad(5)}] will output this: [ ] [ a] [ ab] [ abc] [ abcd] [abcde] [abcdef] [abcdefg] [abcdefgh] If it's used with 2 parameters, then the 1st parameter means the same as if you were using the built-in with only 1 parameter, and the second parameter specifies what to insert instead of space characters. For example: [${""?left_pad(5, "-")}] [${"a"?left_pad(5, "-")}] [${"ab"?left_pad(5, "-")}] [${"abc"?left_pad(5, "-")}] [${"abcd"?left_pad(5, "-")}] [${"abcde"?left_pad(5, "-")}] will output this: [-----] [----a] [---ab] [--abc] [-abcd] [abcde] The 2nd parameter can be a string whose length is greater than 1. Then the string will be inserted periodically, for example: [${""?left_pad(8, ".oO")}] [${"a"?left_pad(8, ".oO")}] [${"ab"?left_pad(8, ".oO")}] [${"abc"?left_pad(8, ".oO")}] [${"abcd"?left_pad(8, ".oO")}] will output this: [.oO.oO.o] [.oO.oO.a] [.oO.oOab] [.oO.oabc] [.oO.abcd] The 2nd parameter must be a string value, and it must be at least 1 character long.
right_pad right_pad built-in padding This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. This is the same as left_pad, but it inserts the characters at the end of the string instead of the beginning of the string. Example: [${""?right_pad(5)}] [${"a"?right_pad(5)}] [${"ab"?right_pad(5)}] [${"abc"?right_pad(5)}] [${"abcd"?right_pad(5)}] [${"abcde"?right_pad(5)}] [${"abcdef"?right_pad(5)}] [${"abcdefg"?right_pad(5)}] [${"abcdefgh"?right_pad(5)}] [${""?right_pad(8, ".oO")}] [${"a"?right_pad(8, ".oO")}] [${"ab"?right_pad(8, ".oO")}] [${"abc"?right_pad(8, ".oO")}] [${"abcd"?right_pad(8, ".oO")}] This will output this: [ ] [a ] [ab ] [abc ] [abcd ] [abcde] [abcdef] [abcdefg] [abcdefgh] [.oO.oO.o] [aoO.oO.o] [abO.oO.o] [abc.oO.o] [abcdoO.o]
contains contains built-in This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. Returns if the substring specified as the parameter to this built-in occurrs in the string. For example: <#if "piceous"?contains("ice")>It contains "ice"</#if> This will output: It contains "ice"
matches matches built-in This is a ``power user'' built-in. Ignore it if you don't know regular expressions. This built-in will work only if you use Java2 platform 1.4 or later. Otherwise it will stop template processing with error. This built-in determines if the string exactly matches the pattern. Also, it returns the list of matching sub-strings. The return value is a multi-type value: Boolean: true, if it the string exactly matches the pattern, otherwise false. For example, "fooo"?matches('fo*') is true, but "fooo bar"?matches('fo*') is false. Sequence: the list of matched substrings of the string. Possibly a 0 length sequence. For example: <#if "fxo"?matches("f.?o")>Matches.<#else>Does not match.</#if> <#assign res = "foo bar fyo"?matches("f.?o")> <#if res>Matches.<#else>Does not match.</#if> Matching sub-strings: <#list res as m> - ${m} </#list> will print: Matches. Does not match. Matching sub-strings: - foo - fyo If the regular expression contains groups (parentheses), then you can access them with the groups built-in: <#assign res = "aa/rx; ab/r;"?matches("(\\w[^/]+)/([^;]+);")> <#list res as m> - ${m} is ${m?groups[1]} per ${m?groups[2]} </#list> This will print: - aa/rx; is aa per rx - ab/r; is ab per r matches accepts an optional 2nd parameter, the flags. Note that it does not support flag f, and ignores the r flag.
number type-casting converting between types number built-in string to number converting string to number parse string as number The string converted to numerical value. The number must be in the same format as you specify numerical values directly in FTL. That is, it must be in the locale independent form, where the decimal separator is dot. In additional the built-in recognizes scientific notation (e.g. "1.23E6", "1.5e-8"). If the string is not in the appropriate format, an error will abort template processing when you try to access this built-in. Known problem: If you use earlier Java2 platform than v1.3, the built-ins will not recognize + prefix and scientific notation.
replace replace built-in It is used to replace all occurrences of a string in the original string with another string. It does not deal with word boundaries. For example: ${"this is a car acarus"?replace("car", "bulldozer")} will print: this is a bulldozer abulldozerus The replacing occurs in left-to-right order. This means that this: ${"aaaaa"?replace("aaa", "X")} will print: Xaa If the 1st parameter is an empty string, then all occurrences of the empty string will be replaced, like "foo"?replace("","|") will evaluate to "|f|o|o|". replace accepts an optional flags parameter, as its 3rd parameter.
rtf rtf built-in escaping output The string as Rich text (RTF text). That is, the string with all: \ replaced with \\ { replaced with \{ } replaced with \}
url url built-in escaping URL encoding URL URL escaping URL encoding url_escaping_charset This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. The string after URL escaping. This means that all non-US-ASCII and reserved URL characters will be escaped with %XX. For example: <#assign x = 'a/b c'> ${x?url} The output will be (assuming that the charset used for the escaping is an US-ASCII compatible charset): a%2Fb%20c Note that it escapes all reserved URL characters (/, =, &, ...etc), so this encoding can be used for encoding query parameter values, for example: <a href="foo.cgi?x=${x?url}&y=${y?url}">Click here...</a> Above no HTML encoding (?htm) was needed, because URL escaping escapes all reserved HTML characters anyway. But watch: always quote the attribute value, and always with normal quotation mark ("), never with apostrophe quotation mark ('), because apostrophe quotation mark is not escaped by the URL escaping. To do URL escaping a charset must be chosen that will be used for calculating the escaped parts (%XX). If you are HTML page author and you don't really understand this, don't worry: the programmers should configure FreeMarker so that it uses the proper charset by default (programmers: see more below...). If you are a more technical minded user, then you may want to know that the charset used is specified by the url_escaping_charset setting, that can be set in template execution time (or, preferably, earlier by the programmers). For example: <#-- This will use the charset specified by the programmers before the template execution has started. --> <a href="foo.cgi?x=${x?url}">foo</a> <#-- Use UTF-8 charset for URL escaping from now: --> <#setting url_escaping_charset="UTF-8"> <#-- This will surely use UTF-8 charset --> <a href="bar.cgi?x=${x?url}">bar</a> Furthermore, you can explicitly specify a charset for a single URL escaping as the parameter to the built-in: <a href="foo.cgi?x=${x?url('ISO-8895-2')}">foo</a> output encoding output charset If the url built-in has no parameter, then it will use the charset specified as the value of the url_escaping_charset setting. This setting should be set by the software that encloses FreeMarker (e.g. a Web application framework), because it is not set (null) by default. If it is not set, then FreeMarker falls back using the value of the output_encoding setting, which is also not set by default, so it is again the task of the enclosing software. If the output_encoding setting is not set either, then the parameterless url built-in can't be executed, and it will cause execution time error. Of course, the url built-in with parameter always works. It's possible to set url_escaping_charset in the template with the setting directive, but it is bad practice, at least in true MVC applications. The output_encoding setting can't be set with the setting directive, so that's surely the task of the enclosing software. You may find more information regarding this here...
split split built-in It is used to split a string into a sequence of strings along the occurrences of another string. For example: <#list "someMOOtestMOOtext"?split("MOO") as x> - ${x} </#list> will print: - some - test - text Note that it is assumed that all occurrences of the separator is before a new item, thus: <#list "some,,test,text,"?split(",") as x> - "${x}" </#list> will print: - "some" - "" - "test" - "text" - "" split accepts an optional flags parameter, as its 2nd parameter.
starts_with starts_with built-in Returns if this string starts with the specified substring. For example "redhead"?starts_with("red") returns boolean true. Also, "red"?starts_with("red") will return true.
string (when used with a string value) Does nothing, just returns the string as-is. The exception is that if the value is a multi-type value (e.g. it is both string and sequence at the same time), then the resulting value will be only a simple string, not a multi-type value. This can be utilized to prevent the artifacts of multi-typing.
trim trim built-in The string without leading and trailing white-space. Example: (${" green mouse "?trim}) The output: (green mouse)
upper_case upper_case built-in The upper case version of the string. For example "GrEeN MoUsE" will be "GREEN MOUSE".
word_list word_list built-in A sequence that contains all words of the string in the order as they appear in the string. Words are continual character sequences that contain any character but white-space. Example: <#assign words = " a bcd, . 1-2-3"?word_list> <#list words as word>[${word}]</#list> will output: [a][bcd,][.][1-2-3]
xhtml xhtml built-in escaping output The string as XHTML text. That is, the string with all: < replaced with &lt; > replaced with &gt; & replaced with &amp; " replaced with &quot; ' replaced with &#39; The only difference between this built-in and the xml built-in is that the xhtml built-in escapes ' as &#39; instead of as &apos;, because some older browsers don't interpret &apos; correctly.
xml xml built-in escaping output The string as XML text. That is, the string with all: < replaced with &lt; > replaced with &gt; & replaced with &amp; " replaced with &quot; ' replaced with &apos;
Common flags Many string built-ins accept an optional string parameter, the so called ``flags''. In this string, each letter influences a certain aspect of the behavior of the built-in. For example, letter i means that the built-in should not differentiate the lower and upper-case variation of the same letter. The order of the letters in the flags string is not significant. This is the complete list of letters (flags): i: Case insensitive: do not differentiate the lower and upper-case variation of the same letter. f: First only. That is, replace/find/etc. only the first occurrence of something. regular expression built-ins r: The substring to find is a regular expression. FreeMarker uses the variation of regular expressions described at http://java.sun.com/j2se/1.4.1/docs/api/java/util/regex/Pattern.html. This flag will work only if you use Java2 platform 1.4 or later. Otherwise it will cause template processing to stop with error. m: Multi-line mode for regular expressions. In multi-line mode the expressions ^ and $ match just after or just before, respectively, a line terminator or the end of the string. By default these expressions only match at the beginning and the end of the entire string. Note that ^ and $ doesn't match the line-break character itself. s: Enables dot-all mode for regular expressions (same as Perl singe-line mode). In dot-all mode, the expression . matches any character, including a line terminator. By default this expression does not match line terminators. c: Permits whitespace and comments in regular expressions. Example: <#assign s = 'foo bAr baar'> ${s?replace('ba', 'XY')} i: ${s?replace('ba', 'XY', 'i')} if: ${s?replace('ba', 'XY', 'if')} r: ${s?replace('ba*', 'XY', 'r')} ri: ${s?replace('ba*', 'XY', 'ri')} rif: ${s?replace('ba*', 'XY', 'rif')} This outputs this: foo bAr XYar i: foo XYr XYar if: foo XYr baar r: foo XYAr XYr ri: foo XYr XYr rif: foo XYr baar This is the table of built-ins that use these common flags, and which supports which flags: Built-in i (ignore case) r (reg. exp.) m (multi-line mode) s (dot-all mode) c (whitesp. and comments) f (first only) replace Yes Yes Only with r Only with r Only with r Yes split Yes Yes Only with r Only with r Only with r No match Yes Ignored Yes Yes Yes No
Built-ins for numbers number built-ins Related FAQs: Do you have things like 1,000,000 or 1 000 000 instead of 1000000, or something like 3.14 instead of 3,14 or vice versa? See this and this FAQ entry, also note the c built-in above.
c type-casting converting between types format number This built-in exists since FreeMarker 2.3.3. This built-in converts a number to string for ``computer audience'' as opposed to human audience. That is, it formats with the rules that programming languages used to use, which is independent of all the locale and number format settings of FreeMarker. It always uses dot as decimal separator, and it never uses grouping separators (like 3,000,000), nor exponential form (like 5E20), nor superfluous leading or trailing 0-s (like 03 or 1.0), nor + sign (like +1). It will print at most 16 digits after the decimal dot, and thus numbers whose absolute value is less than 1E-16 will be shown as 0. This built-in is crucial because be default (like with ${x}) numbers are converted to strings with the locale (language, country) specific number formatting, which is for human readers (like 3000000 is possibly printed as 3,000,000). When the number is printed not for human audience (e.g., for a database record ID used as the part of an URL, or as invisible field value in a HTML form, or for printing CSS/JavaScript numerical literals) this built-in must be used to print the number (i.e., use ${x?c} instead of ${x}), or else the output will be possibly broken depending on the current number formatting settings and locale (like the decimal point is not dot, but comma in many countries) and the value of the number (like big numbers are possibly ``damaged'' by grouping separators).
string (when used with a numerical value) type-casting converting between types string built-in format number Converts a number to a string. It uses the default format that the programmer has specified. You can also specify a number format explicitly with this built-in, as it will be shown later. There are four predefined number formats: computer, currency, number, and percent. The exact meaning of these is locale (nationality) specific, and is controlled by the Java platform installation, rather than by FreeMarker, except for computer, which uses the same formatting as the c built-in. You can use these predefined formats like this: <#assign x=42> ${x} ${x?string} <#-- the same as ${x} --> ${x?string.number} ${x?string.currency} ${x?string.percent} ${x?string.computer} If your locale is US English, this will certainly produce: 42 42 42 $42.00 4,200% 42 The output of first three expressions is identical because the first two expressions use the default format, which is "number" here. You can change this default using a setting: <#setting number_format="currency"> <#assign x=42> ${x} ${x?string} <#-- the same as ${x} --> ${x?string.number} ${x?string.currency} ${x?string.percent} Will now output: $42.00 $42.00 42 $42.00 4,200% since the default number format was set to "currency". Beside the three predefined formats, you can use arbitrary number format patterns written in Java decimal number format syntax: <#assign x = 1.234> ${x?string("0")} ${x?string("0.#")} ${x?string("0.##")} ${x?string("0.###")} ${x?string("0.####")} ${1?string("000.00")} ${12.1?string("000.00")} ${123.456?string("000.00")} ${1.2?string("0")} ${1.8?string("0")} ${1.5?string("0")} <-- 1.5, rounded towards even neighbor ${2.5?string("0")} <-- 2.5, rounded towards even neighbor ${12345?string("0.##E0")} outputs this: 1 1.2 1.23 1.234 1.234 001.00 012.10 123.46 1 2 2 <-- 1.5, rounded towards even neighbor 2 <-- 2.5, rounded towards even neighbor 1.23E4 Following the financial and statistics practice, the rounding goes according the so called half-even rule, which means rounding towards the nearest ``neighbor'', unless both neighbors are equidistant, in which case, it rounds towards the even neighbor. This was visible in the above example if you look at the rounding of 1.5 and of 2.5, as both were rounded to 2, since 2 is even, but 1 and 3 are odds. Apart from the Java decimal syntax patterns, you can also write ${aNumber?string("currency")} and like, that will do the same as ${aNumber?string.currency} and like. As it was shown for the predefined formats earlier, the default formatting of the numbers can be set in the template: <#setting number_format="0.##"> ${1.234} outputs this: 1.23 Note that the number formatting is locale sensitive: <#setting locale="en_US"> US people write: ${12345678?string(",##0.00")} <#setting locale="hu"> Hungarian people write: ${12345678?string(",##0.00")} outputs this: US people write: 12,345,678.00 Hungarian people write: 12 345 678,00
round, floor, ceiling rounding floor built-in ceiling built-in round built-in The rounding built-ins exist since FreeMarker 2.3.13. Converts a number to a whole number using the specified rounding rule: round: Rounds to the nearest whole number. If the number ends with .5, then it rounds upwards (i.e., towards positive infinity) floor: Rounds the number downwards (i.e., towards neagative infinity) ceiling: Rounds the number upwards (i.e., towards positive infinity) Example: <#assign testlist=[ 0, 1, -1, 0.5, 1.5, -0.5, -1.5, 0.25, -0.25, 1.75, -1.75]> <#list testlist as result> ${result} ?floor=${result?floor} ?ceiling=${result?ceiling} ?round=${result?round} </#list> Prints: 0 ?floor=0 ?ceiling=0 ?round=0 1 ?floor=1 ?ceiling=1 ?round=1 -1 ?floor=-1 ?ceiling=-1 ?round=-1 0.5 ?floor=0 ?ceiling=1 ?round=1 1.5 ?floor=1 ?ceiling=2 ?round=2 -0.5 ?floor=-1 ?ceiling=0 ?round=0 -1.5 ?floor=-2 ?ceiling=-1 ?round=-1 0.25 ?floor=0 ?ceiling=1 ?round=0 -0.25 ?floor=-1 ?ceiling=0 ?round=0 1.75 ?floor=1 ?ceiling=2 ?round=2 -1.75 ?floor=-2 ?ceiling=-1 ?round=-2 These built-ins may be useful in pagination operations and like. If you just want to display numbers in rounded form, then you should rather use the string built-in or the number_format setting.
Built-ins for dates date built-ins time built-ins
string (when used with a date value) type-casting converting between types string built-in format date converting date to string converting time to string time to string date to string This built-in converts a date to a string, with the specified formatting. (when the default format dictated by the date_format, time_format and datetime_format settings of FreeMarker are good for you, then you do not need this built-in.) The format can be one of the predefined formats, or you can specify the formatting pattern explicitly. The predefined formats are short, medium, long, and full which define how verbose the resulting text will be. For example, if the locale of the output is U.S. English, and the time zone is the U.S. Pacific Time zone, then this: ${openingTime?string.short} ${openingTime?string.medium} ${openingTime?string.long} ${openingTime?string.full} ${nextDiscountDay?string.short} ${nextDiscountDay?string.medium} ${nextDiscountDay?string.long} ${nextDiscountDay?string.full} ${lastUpdated?string.short} ${lastUpdated?string.medium} ${lastUpdated?string.long} ${lastUpdated?string.full} will prints something like this: 12:45 PM 12:45:09 PM 12:45:09 PM CEST 12:45:09 PM CEST 4/20/07 Apr 20, 2007 April 20, 2007 Friday, April 20, 2007 4/20/07 12:45 PM Apr 20, 2007 12:45:09 PM April 20, 2007 12:45:09 PM CEST Friday, April 20, 2007 12:45:09 PM CEST The exact meaning of short, medium, long, and full depends on the current locale (language). Furthermore, it is specified not by FreeMarker, but the Java platform implementation you run FreeMarker on. For dates that contains both date and time part, you can specify the length of the date and time part independently: ${lastUpdated?string.short_long} <#-- short date, long time --> ${lastUpdated?string.medium_short} <#-- medium date, short time --> will output: 4/8/03 9:24:44 PM PDT Apr 8, 2003 9:24 PM Note that ?string.short is the same as ?string.short_short, ?string.medium is the same as ?string.medium_medium, etc. Unfortunately, because of the limitations of the Java platform, it can happen that you have date variables in the data-model, where FreeMarker can't decide if the variable stores only date part (year, month, day), only time part (hour, minute, second, millisecond) or both. In this case, FreeMarker don't know how to display the date when you write something like ${lastUpdated?string.short} or simply ${lastUpdated}, and thus it will stop with error. To prevent this, you can help FreeMarker with the ?date, ?time and ?datetime built-ins. For example: ${lastUpdated?datetime?string.short}. Ask the programmer if certain variables of the data-model has this problem, or always use ?date, ?time and ?datetime built-ins. Instead of using the predefined formats, you can specify the formatting pattern explicitly with ?string(pattern_string). The pattern uses Java date format syntax. Example: ${lastUpdated?string("yyyy-MM-dd HH:mm:ss zzzz")} ${lastUpdated?string("EEE, MMM d, ''yy")} ${lastUpdated?string("EEEE, MMMM dd, yyyy, hh:mm:ss a '('zzz')'")} will output: 2003-04-08 21:24:44 Pacific Daylight Time Tue, Apr 8, '03 Tuesday, April 08, 2003, 09:24:44 PM (PDT) Unlike with the predefined formats, you never need to use ?date, ?time and ?datetime with explicitly given patterns, since with the pattern you tell FreeMarker what parts of the date to show. However, FreeMarker will trust you blindly, so you can show "noise" if you display parts that are actually not stored in the variable. For example, ${openingTime?string("yyyy-MM-dd hh:mm:ss a")}, where openingTime stores only time, will display 1970-01-01 09:24:44 PM. The pattern string also can be "short", "medium", ..., "short_medium", ...etc. These are the same as if you would use the predefined formats with the dot syntax: someDate?string("short") and someDate?string.short are equivalent. See also: the interpolation of dates
date, time, datetime (when used with a date value) type-casting converting between types date built-in time built-in datetime built-in These built-ins can be used to specify which parts of the date variable are in use: date: Only the year, month and day parts are used. time: Only the hour, minute, second and millisecond parts are used. datetime: Both the date and the time parts are used. In optimal case, you do not need to use these built-ins. Unfortunately, because of the technical limitations of the Java platform, FreeMarker sometimes can't find out which parts of the date are in use (i.e. only the year+month+day, or only hour+minute+second+millisecond, or both); ask the programmers which variables has this problem. If FreeMarker has to execute an operation where this information is needed -- such as displaying the date as text -- but it does not know which parts are in use, it will stop with error. This is when you have to use these built-ins. For example, assume openingTime is a such problematic variable: <#assign x = openingTime> <#-- no problem can occur here --> ${openingTime?time} <#-- without ?time it would fail --> <#-- For the sake of better understanding, consider this: --> <#assign openingTime = openingTime?time> ${openingTime} <#-- this will work now --> There is another usage of these built-ins: to truncate dates. For example: Last updated: ${lastUpdated} <#-- assume that lastUpdated is a date-time value --> Last updated date: ${lastUpdated?date} Last updated time: ${lastUpdated?time} will output something like: Last updated: 04/25/2003 08:00:54 PM Last updated date: 04/25/2003 Last updated time: 08:00:54 PM If the left side of the ? is string, then these built-ins convert strings to date variable.
iso_... type-casting converting between types iso built-in iso_... built-ins format date converting date to string converting time to string time to string date to string ISO 8601 These built-ins convert a date, time or date-time value to string that follows ISO 8601 "extended" format. This built-in has several variations: iso_utc, iso_local, iso_utc_nz, iso_local_nz, iso_utc_m, iso_utc_m_nz, etc. The name is constructed from the following words in this order, each separated with a _ from the next: iso (required) Either utc or local (required (except when it's given with a parameter, but see that later)): Specifies whether you want to print the date according to UTC or according the current time zone. The current time zone is decided by the time_zone FreeMarker setting and is normally configured by the programmers outside the templates (but it can also be set in a template, like <#setting time_zone="America/New_York"> for example). Either h or m or ms (optional): The accuracy of the time part. When omitted, it defaults to seconds accuracy (like 12:30:18). h means hours accuracy (like 12), m means minutes accuracy (12:30), and ms means milliseconds accuracy (12:30:18.25, where we have 250 ms). Note that when using ms, the milliseconds are displayed as fraction seconds (following the standard) and will not have trailing 0-s. Thus, if the the millisecond part happens to be 0, the whole fraction second part will be omitted. Also note that the fraction seconds are always separated with a dot , not with comma (to follow the Web conventions and the XML Schema date/time format). nz (optional): When present, the time zone offset (like +02:00 or or -04:30 or Z) will not be displayed. Otherwise it will be displayed, except for date-only values (as dates with zone offset doesn't appear in ISO 8601:2004). Since FreeMarker 2.3.19, the offset always contains the minutes for XML Schema date/time format compliance. Example: <#assign aDateTime = .now> <#assign aDate = aDateTime?date> <#assign aTime = aDateTime?time> Basic formats: ${aDate?iso_utc} ${aTime?iso_utc} ${aDateTime?iso_utc} Different accuracies: ${aTime?iso_utc_ms} ${aDateTime?iso_utc_m} Local time zone: ${aDateTime?iso_local} A possible output (depends on current time and time zone): Basic formats: 2011-05-16 21:32:13Z 2011-05-16T21:32:13Z Different accuracies: 21:32:13.868Z 2011-05-16T21:32Z Local time zone: 2011-05-16T23:32:13+02:00 There is yet another group of iso_... built-in variants, where you omit the local or utc word from the name and instead specify the time zone as a parameter to the built-in. Example: <#assign aDateTime = .now> ${aDateTime?iso("UTC")} ${aDateTime?iso("GMT-02:30")} ${aDateTime?iso("Europe/Rome")} The usual variations are supported: ${aDateTime?iso_m("GMT+02")} ${aDateTime?iso_m_nz("GMT+02")} ${aDateTime?iso_nz("GMT+02")} A possible output (depends on current time and time zone): 2011-05-16T21:43:58Z 2011-05-16T19:13:58-02:30 2011-05-16T23:43:58+02:00 The usual variations are supported: 2011-05-16T23:43+02:00 2011-05-16T23:43 2011-05-16T23:43:58 If the time zone parameter can't be interpreted, the template processing will be terminated with error. The parameter can be a java.util.TimeZone object too (which is possibly the return value of a Java method, or it's in the data-model), not just a string.
Built-ins for booleans boolean built-ins
string (when used with a boolean value) boolean printing type-casting converting between types string built-in format boolean Converts a boolean to a string. You can use it in two ways: As foo?string: This will convert the boolean to string using the default strings for representing true and false values. By default, true is rendered as "true" and false is rendered as "false". This is mostly useful if you generate source code with FreeMarker, since the values are not locale (language, country) sensitive. To change these default strings, you can use the boolean_format setting. Note, that if the variable is multi-type variable that is both boolean and string, then the string value of the variable will be returned. As foo?string("yes", "no"): This will return the first parameter (here: "yes") if the boolean is true, otherwise the second parameter (here: "no"). Note that the return value is always a string; if the parameters were numbers, they would be converted to strings first.
Built-ins for sequences sequence built-ins
first first built-in The first subvariable of the sequence. Template processing will die with error if the sequence is empty.
last last built-in The last subvariable of the sequence. Template processing will die with error if the sequence is empty.
seq_contains seq_contains built-in This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. The seq_ prefix is required in the built-in name to differentiate it from the contains built-in that searches a substring in a string (since a variable can be both string and sequence on the same time). Tells if the sequence contains the specified value. It has 1 parameter, the value to find. Example: <#assign x = ["red", 16, "blue", "cyan"]> "blue": ${x?seq_contains("blue")?string("yes", "no")} "yellow": ${x?seq_contains("yellow")?string("yes", "no")} 16: ${x?seq_contains(16)?string("yes", "no")} "16": ${x?seq_contains("16")?string("yes", "no")} The output will be: "blue": yes "yellow": no 16: yes "16": no To find the value the built-in uses FreeMarker's comparison rules (as if you was using == operator), except that comparing two values of different types or of types for which FreeMarker doesn't support comparison will not cause error, just will be evaluated as the two values are not equal. Thus, you can use it only to find scalar values (i.e. string, number, boolean or date/time values). For other types the result will be always false. For fault tolerance, this built-in also works with collections.
seq_index_of seq_index_of built-in This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. The seq_ prefix is required in the built-in name to differentiate it from the index_of built-in that searches a substring in a string (since a variable can be both string and sequence on the same time). Returns the index of the first occurrence of a value in the sequence, or -1 if the sequence doesn't contain the specified value. The value to find is specified as the first parameter. For example this template: <#assign colors = ["red", "green", "blue"]> ${colors?seq_index_of("blue")} ${colors?seq_index_of("red")} ${colors?seq_index_of("purple")} will output this: 2 0 -1 To find the value the built-in uses FreeMarker's comparison rules (as if you was using == operator), except that comparing two values of different types or of types for which FreeMarker doesn't support comparison will not cause error, just will be evaluated as the two values are not equal. Thus, you can use it only to find scalar values (i.e. string, number, boolean or date/time values). For other types the result will be always -1. The index where the searching is started can be optionally given as the 2nd parameter. This may be useful if the same item can occur for multiple times in the same sequence. There is no restriction on the numerical value of the second parameter: if it is negative, it has the same effect as if it were zero, and if it is greater than the length of the sequence, it has the same effect as if it were equal to the length of the sequence. Decimal values will be truncated to integers. For example: <#assign names = ["Joe", "Fred", "Joe", "Susan"]> No 2nd param: ${names?seq_index_of("Joe")} -2: ${names?seq_index_of("Joe", -2)} -1: ${names?seq_index_of("Joe", -1)} 0: ${names?seq_index_of("Joe", 0)} 1: ${names?seq_index_of("Joe", 1)} 2: ${names?seq_index_of("Joe", 2)} 3: ${names?seq_index_of("Joe", 3)} 4: ${names?seq_index_of("Joe", 4)} will output this: No 2nd param: 0 -2: 0 -1: 0 0: 0 1: 2 2: 2 3: -1 4: -1
seq_last_index_of seq_last_index_of built-in This built-in is available since FreeMarker 2.3.1. It doesn't exist in 2.3. The seq_ prefix is required in the built-in name to differentiate it from the last_index_of built-in that searches a substring in a string (since a variable can be both string and sequence on the same time). Returns the index of the last occurrence of a value in the sequence, or -1 if the sequence doesn't contain the specified value. That is, it is the same as seq_index_of, just it searches backward starting from the last item of the sequence. It also supports the optional 2nd parameter that specifies the index where the searching is started. For example: <#assign names = ["Joe", "Fred", "Joe", "Susan"]> No 2nd param: ${names?seq_last_index_of("Joe")} -2: ${names?seq_last_index_of("Joe", -2)} -1: ${names?seq_last_index_of("Joe", -1)} 0: ${names?seq_last_index_of("Joe", 0)} 1: ${names?seq_last_index_of("Joe", 1)} 2: ${names?seq_last_index_of("Joe", 2)} 3: ${names?seq_last_index_of("Joe", 3)} 4: ${names?seq_last_index_of("Joe", 4)} will output this: No 2nd param: 2 -2: -1 -1: -1 0: 0 1: 0 2: 2 3: 2 4: 2
reverse reverse built-in The sequence with reversed order.
size size built-in The number of subvariables in sequence (as a numerical value). The highest possible index in sequence s is s?size - 1 (since the index of the first subvariable is 0) assuming that the sequence has at least one subvariable.
sort sort built-in sequence sorting Returns the sequence sorted in ascending order. (For descending order use this and then the reverse built in.) This will work only if all subvariables are strings, or if all subvariables are numbers, or if all subvariables are date values (date, time, or date+time), or if all subvariables are booleans (since 2.3.17). If the subvariables are strings, it uses locale (language) specific lexical sorting (which is usually not case sensitive). For example: <#assign ls = ["whale", "Barbara", "zeppelin", "aardvark", "beetroot"]?sort> <#list ls as i>${i} </#list> will print (with US locale at least): aardvark Barbara beetroot whale zeppelin
sort_by sort_by built-in sequence sorting Returns the sequence of hashes sorted by the given hash subvariable in ascending order. (For descending order use this and then the reverse built in.) The rules are the same as with the sort built-in, except that the subvariables of the sequence must be hashes, and you have to give the name of a hash subvariable that will decide the order. For example: <#assign ls = [ {"name":"whale", "weight":2000}, {"name":"Barbara", "weight":53}, {"name":"zeppelin", "weight":-200}, {"name":"aardvark", "weight":30}, {"name":"beetroot", "weight":0.3} ]> Order by name: <#list ls?sort_by("name") as i> - ${i.name}: ${i.weight} </#list> Order by weight: <#list ls?sort_by("weight") as i> - ${i.name}: ${i.weight} </#list> will print (with US locale at least): Order by name: - aardvark: 30 - Barbara: 53 - beetroot: 0.3 - whale: 2000 - zeppelin: -200 Order by weight: - zeppelin: -200 - beetroot: 0.3 - aardvark: 30 - Barbara: 53 - whale: 2000 If the subvariable that you want to use for the sorting is on a deeper level (that is, if it is a subvariable of a subvariable and so on), then you can use a sequence as parameter, that specifies the names of the subvariables that lead down to the desired subvariable. For example: <#assign members = [ {"name": {"first": "Joe", "last": "Smith"}, "age": 40}, {"name": {"first": "Fred", "last": "Crooger"}, "age": 35}, {"name": {"first": "Amanda", "last": "Fox"}, "age": 25}]> Sorted by name.last: <#list members?sort_by(['name', 'last']) as m> - ${m.name.last}, ${m.name.first}: ${m.age} years old </#list> will print (with US locale at least): Sorted by name.last: - Crooger, Fred: 35 years old - Fox, Amanda: 25 years old - Smith, Joe: 40 years old
chunk chunk built-in tabular printing of sequences columnar printing of sequences This built-in exists since FreeMarker 2.3.3. This built-in splits a sequence into multiple sequences of the size given with the 1st parameter to the built-in (like mySeq?chunk(3)). The result is the sequence of these sequences. The last sequence is possibly shorter than the given size, unless the 2nd parameter is given (like mySeq?chunk(3, '-')), that is the item used to make up the size of the last sequence to the given size. Example: <#assign seq = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']> <#list seq?chunk(4) as row> <#list row as cell>${cell} </#list> </#list> <#list seq?chunk(4, '-') as row> <#list row as cell>${cell} </#list> </#list> The output will be: a b c d e f g h i j a b c d e f g h i j - - This built in is mostly for outputting sequnces in tabular/columnar format. When used with HTML tables, the 2nd parameter is often "\xA0" (that is the code of the no-break space character, also known as ``nbsp''), so the border of the empty TD-s will not be missing. The 1st parameter must be a number that is at least 1. If the number is not integer, it will be silently rounded down to integer (i.e. both 3.1 and 3.9 will be rounded to 3). The 2nd parameter can be of any type and value.
Built-ins for hashes hash built-ins
keys keys built-in A sequence that contains all the lookup keys in the hash. Note that not all hashes support this (ask the programmer if a certain hash allows this or not). <#assign h = {"name":"mouse", "price":50}> <#assign keys = h?keys> <#list keys as key>${key} = ${h[key]}; </#list> Output: name = mouse; price = 50; Since hashes do not define an order for their subvariables in general, the order in which key names are returned can be arbitrary. However, some hashes maintain a meaningful order (ask the programmer if a certain hash does that or not). For example, hashes created with the above {...} syntax preserve the same order as you have specified the subvariables.
values values built-in A sequence that contains all the variables in the hash. Note that not all hashes support this (ask the programmer if a certain hash allows this or not). As of the order in which the values are returned, the same applies as with the keys built-in; see there.
Built-ins for nodes (for XML) node built-ins Note that the variables returned by these built-ins are generated by the node variable implementation it is used with. This means that the returned variables can have extra features in additional to what it stated here, for example, with the XML DOM nodes the sequence retuned by the children built-in also can be used as hash and maybe as string, as it is described in the part about XML processing.
children children built-in A sequence that contains all of this node's child nodes (i.e. immediate descendant nodes). XML: This is almost the same as special hash key *, except that it returns all nodes, not only elements. So the possible children are element nodes, text nodes, comment nodes, processing instruction nodes, etc. but not attribute nodes. Attribute nodes are excluded from the sequence.
parent parent built-in The node that is this node's immediate parent in the node tree. The root node has no parent node, so for the root node, the expression node?parent?? evaluates to false. XML: Note that the value returned by this built-in is also a sequence (same as the result of XPath expression .., when you write someNode[".."]). Also note that for attribute nodes, it returns the element the attribute belongs to, despite that attribute nodes are not counted as children of the element.
root root built-in The node that is the root of the tree of nodes to which this node belongs. XML: According to W3C, the root of an XML document is not the topmost element node, but the document itself, which is the parent of the topmost element. For example, if you want to get the topmost element of the XML (the so called ``document element''; do not mix it with the ``document''), which is called foo, then you have to write someNode?root.foo. If you write just someNode?root, then you get the document itself, and not the document element.
ancestors ancestors built-in A sequence that contains all the node's ancestors, starting with the immediate parent and ending with the root node. The result of this built-in is also a method, by which you can filter the result with the full-qualified name of the node. For example as node?ancestors("section") to get the sequence of all ancestors with name section.
node_name node_name built-in Returns the string that is used to determine what user-defined directive to invoke to handle this node when it is ``visited''. See: the visit and recurse directives. XML: If the node is an element or attribute, then the string will be the local (prefix free) name of the element or attribute. Otherwise the name usually starts with @ followed by the node type. See this table. Note that this node name is not the same as the node name returned in the DOM API; the goal of FreeMarker node names is to give the name of the used-defined directive that will process the node.
node_type node_type built-in A string that describes the type of node this is. FreeMarker does not define the exact meaning of node type; it depends on what your variables are modeling. It's possible that a node doesn't support node type at all. In this case, the built-in evaluates to an undefined value, so you can't use the returned value. (You can still check if a node supports the type property with node?node_type??.) XML: The possible values are: "attribute", "text", "comment", "document_fragment", "document", "document_type", "element", "entity", "entity_reference", "notation", "pi". Note that a there is no "cdata" type, because CDATA is considered as plain text node.
node_namespace node_namespace built-in Returns the namespace string of the node. FreeMarker does not define the exact meaning of node namespace; it depends on what your node variables are modeling. It's possible that a node doesn't have any node namespace defined. In this case, the built-in should evaluate to undefined variable (i.e. node?node_namespace?? is false), so you can't use the returned value. XML: In the case of XML, it's the XML namespace URI (such as "http://www.w3.org/1999/xhtml"). If an element or attribute node does not use XML namespace, then this built-in evaluates to an empty string. For other XML nodes this built-in always return undefined variable.
Seldom used and expert built-ins These are the built-ins that normally you should not use, but in exceptional situations (debugging, advanced macros) they can be useful. If you need to use these in your normal page templates, you may revisit the data-model so you don't need to use these.
byte, double, float, int, long, short type-casting converting between types byte built-in double built-in float built-in int built-in long built-in short built-in converting date to long date to long Returns a SimpleNumber which contains the same value as the original variable, but uses java.lang.Type for the internal representation of the value. This is useful if a method is overloaded, or if a TemplateModel unwrapper has problem with automatically choosing the suitable java.lang.* type. Note that since version 2.3.9 the unwrapper has been improved substantially, so you will hardly ever need to use these built-ins to convert between numerical types, except for resolving ambiguity in overloaded method invocation. The long built-in can also be used with date, time and date-time values to get the value as java.util.Date.getTime() would return. This is useful if you have to call a Java methods that expect a timestamp as a long. This conversion is not automatic.
number_to_date, number_to_time, number_to_datetime type-casting converting between types number_to_date built-in number_to_datetime built-in number_to_time built-in converting long to date long to date These are used to convert a number (usually a Java long) to a date, time or date-time, respectively. This does them same as new java.util.Date(long) in Java, that is, the number is interpreted as the milliseconds passed since the epoch. The number can be anything and of any type as far as its value fits into a long. If the number isn't a whole number, it will be rounded to whole with half-up rule. This conversion is not automatic. Example: ${1305575275540?number_to_datetime} ${1305575275540?number_to_date} ${1305575275540?number_to_time} The output will be something like this (depending on the current locale and time zone): May 16, 2011 3:47:55 PM May 16, 2011 3:47:55 PM
eval eval evaluate string This built-in evaluates a string as an FTL expression. For example "1+2"?eval returns number 3.
has_content has_content built-in It is true if the variable exists (and isn't Java null) and is not ``empty'', otherwise it is false. The meaning of ``empty'' depends on the concrete case. This follows intuitive common-sense ideas. The following are empty: a string with 0 length, sequence or hash with no subvariables, a collection which has passed the last element. If the value is not a string or sequence or hash or collection, then it counts as non-empty if it's a number or a date or a boolean (e.g. 0 and false are not empty), otherwise it counts as empty. Note that when your data-model implements multiple template model interfaces you may get unexpected results. However, when in doubt you can use always use expr!?size > 0 or expr!?length > 0 instead of expr?has_content. This buit-in is exceptional in that you can use the parentheses trick like with the default value operator. That is, you can write both product.color?has_content and (product.color)?has_content. The first doesn't handle the case when product is missing, the last does.
interpret interpret built-in This built-in interprets a string as a FTL template, and returns an user-defined directive that - when applied to any block - executes the template just as if it was included at that point. Example: <#assign x=["a", "b", "c"]> <#assign templateSource = r"<#list x as y>${y}</#list>"> <#-- Note: That r was needed so that the ${y} is not interpreted above --> <#assign inlineTemplate = templateSource?interpret> <@inlineTemplate /> The output: abc As you can see, inlineTemplate is a user-defined directive that, when executed, runs the template that was generated on-the-fly using the interpret. You can also apply this built-in to a two-element sequence. In this case the first element of the sequence is the template source, and the second element is a name for the inline template. It can be useful to give an explicit name to the inline template for debugging purposes. So, you could have written: <#assign inlineTemplate = [templateSource, "myInlineTemplate"]?interpret> as well in the above template. Note that giving the inline template a name has no immediate effect - it is only useful as an extra bit of information if you get an error report.
is_... is_... built-in type checking These built-ins check the type of a variable, and returns true or false depending on the type. The list of is_... built-ins: Built-in Returns true if the value is a ... is_string string is_number number is_boolean boolean is_date date (all types: date-only, time-only and date-time) is_method method is_transform transform is_macro macro is_hash hash is_hash_ex extended hash (i.e. supports ?keys and ?values) is_sequence sequence is_collection collection is_enumerable sequence or collection is_indexable sequence is_directive Whatever kind of directive (for example a macro, or TemplateDirectiveModel, TemplateTransformModel, etc.) is_node node
namespace namespace built-in This built-in returns the namespace (i.e. the ``gate'' hash to the namespace) associated with a macro variable. You can use it with macros only.
new instantiating variable new built-in This is to create a variable of a certain TemplateModel implementation. On the left side of ? you specify a string, the full-qualified class name of a TemplateModel implementation. The result is a method variable that calls the constructor, and returns the new variable. Example: <#-- Creates an user-defined directive be calling the parameterless constructor of the class --> <#assign word_wrapp = "com.acmee.freemarker.WordWrapperDirective"?new()> <#-- Creates an user-defined directive be calling the constructor with one numerical argument --> <#assign word_wrapp_narrow = "com.acmee.freemarker.WordWrapperDirective"?new(40)> For more information about how the constructor parameters are unwrapped and how overloaded constructor is chosen, read: This built-in can be a security concern because the template author can create arbitrary Java objects and then use them, as far as they implement TemplateModel. Also the template author can trigger static initialization for classes that don't even implement TemplateModel. You can (since 2.3.17) restrict the classes accessible with this built-in using Configuration.setNewBuiltinClassResolver(TemplateClassResolver) or the new_builtin_class_resolver setting. See the Java API docs for more information. If you are allowing not-so-much-trusted users to upload templates then you should definitely look into this topic.
Directive Reference directive
Alphabetical index directive assign attempt break: in switch, in list case compress default else elseif escape fallback function flush ftl global if import include list local lt macro nested noescape nt recover recurse return: in macro, in function rt setting stop switch t User-defined directive (<@...>) visit If you don't find a directive here that you have seen in a working template, probably you will find it in:
if, else, elseif if directive else directive elseif directive
Synopsis <#if condition> ... <#elseif condition2> ... <#elseif condition3> ... ... <#else> ... </#if> Where: condition, condition2, ...etc.: Expression evaluates to a boolean value.
Description You can use if, elseif and else directives to conditionally skip a section of the template. The condition-s must evaluate to a boolean value, or else an error will abort template processing. The elseif-s and else-s must occur inside if (that is, between the if start-tag and end-tag). The if can contain any number of elseif-s (including 0) and at the end optionally one else. Examples: if with 0 elseif and no else: <#if x == 1> x is 1 </#if> if with 0 elseif and else: <#if x == 1> x is 1 <#else> x is not 1 </#if> if with 2 elseif and no else: <#if x == 1> x is 1 <#elseif x == 2> x is 2 <#elseif x == 3> x is 3 </#if> if with 3 elseif and else: <#if x == 1> x is 1 <#elseif x == 2> x is 2 <#elseif x == 3> x is 3 <#elseif x == 4> x is 4 <#else> x is not 1 nor 2 nor 3 nor 4 </#if> To see more about boolean expressions, see: . You can nest if directives (of course): <#if x == 1> x is 1 <#if y == 1> and y is 1 too <#else> but y is not </#if> <#else> x is not 1 <#if y < 0> and y is less than 0 </#if> </#if> How to test if x is greater than 1? <#if x > 1> will be wrong, as FreeMarker will interpret the first > as the end of the tag. Thus, either write <#if (x > 1)> or <#if x &gt; 1>.
switch, case, default, break switch directive case directive default directive break directive
Synopsis <#switch value> <#case refValue1> ... <#break> <#case refValue2> ... <#break> ... <#case refValueN> ... <#break> <#default> ... </#switch> Where: value, refValue1, etc.: Expressions evaluates to scalars of the same type.
Description The usage of this directive is not recommended, as it is error-prone because of the fall-through behavior. Use elseif-s instead unless you want to exploit the fall-through behavior. Switch is used to choose a fragment of template depending on the value of an expression: <#switch being.size> <#case "small"> This will be processed if it is small <#break> <#case "medium"> This will be processed if it is medium <#break> <#case "large"> This will be processed if it is large <#break> <#default> This will be processed if it is neither </#switch> Inside the switch must be one or more <#case value>, and after all such case tags optionally one <#default>. When FM reaches the switch directive, it chooses a case directive where refValue equals with value and continues the processing of the template there. If there is no case directive with appropriate value then it continues processing at the default directive if that exists, otherwise it continues the processing after the end-tag of switch. And now comes the confusing thing: when it has chosen a case directive, it will continue the processing there, and will go ahead until it reaches a break directive. That is, it will not automatically leave the switch directive when it reaches another case directive or the <#default> tag. Example: <#switch x> <#case x = 1> 1 <#case x = 2> 2 <#default> d </#switch> If x is 1, then it will print 1 2 d; if x is 2 then it will print 2 d; if x is 3 then it will print d. This is the mentioned fall-through behavior. The break tag instructs FM to immediately skip past the switch end-tag.
list, break list directive break directive sequence iterate
Synopsis <#list sequence as item> ... </#list> Where: sequence: Expressions evaluates to a sequence or collection item: Name of the loop variable (not an expression)
Description You can use the list directive to process a section of template for each variable contained within a sequence. The code between the start-tag and end-tag will be processed for the 1st subvariable, then for the 2nd subvariable, then for the 3rd subvariable, etc until it passes the last one. For each such iteration the loop variable will contain the current subvariable. There are two special loop variables available inside the list loop: item_index: This is a numerical value that contains the index of the current item being stepped over in the loop. item_has_next: Boolean value that tells if the current item the last in the sequence or not. Example 1: <#assign seq = ["winter", "spring", "summer", "autumn"]> <#list seq as x> ${x_index + 1}. ${x}<#if x_has_next>,</#if> </#list> will output: 1. winter, 2. spring, 3. summer, 4. autumn Example 2: You can use list to count between two numbers, using a numerical range sequence expression: <#assign x=3> <#list 1..x as i> ${i} </#list> The output will be: 1 2 3 Note that the above example will not work as you may expected if x is 0, as then it will print 0 and -1. You can leave the list loop before it passes the last subvariable of the sequence with the break directive. For example this will print ``winter'' and ``spring'' only: <#list seq as x> ${x} <#if x = "spring"><#break></#if> </#list> Note that if you turn on the classic compatible mode, then the list accepts a scalar as well and treats it as a single-element sequence. In general, it is best to avoid using collection that wraps an Iterator as parameters to list and use collection that wraps java.util.Collection or sequence whenever possible. There are situations however, when you only have an Iterator at your disposal. Note that if you pass an collection that wraps an Iterator to the list, you can iterate over its elements only once since Iterators are by their nature one-off objects. When you try to list a such collection variable for the second time, an error will abort template processing.
include include directive
Synopsis <#include path> or <#include path options> Where: path: The path of the file to include; an expression that evaluates to a string. (With other words, it doesn't have to be a fixed string, it can also be something like, for example, profile.baseDir + "/menu.ftl".) options: One or more of these: encoding=encoding, parse=parse encoding: Expression evaluates to string parse: Expression evaluates to boolean (also accepts a few string values for backward compatibility)
Description You can use it to insert another FreeMarker template file (specified by the path parameter) into your template. The output from the included template is inserted at the point where the include tag occurs. The included file shares the variables with the including template, similarly like if it was copy-pasted into it. The include directive is not replaced by the content of the included file, it just processes the included file each time when FreeMarker reaches the include directive in the course of template processing. So for example if the include is inside a listloop, you can specify different file names in each cycle. This directive is not be confused with the JSP (Servlet) include, as it doesn't involve the Servlet container at all, just processes another FreeMarker template, without "leaving" FreeMarker. Regarding how to do a "JSP include" read this... The path parameter can be a relative path like "foo.ftl" and "../foo.ftl", or an absolute like "/foo.ftl". Relative paths are relative to the directory of the template that uses the import directive. Absolute paths are relative to a base (often referred as the ''root directory of the templates'') that the programmer defines when he configures FreeMarker. This is different than the way it worked prior FreeMarker 2.1, where the path was always absolute. To preserve the old behavior, enable the classic compatible mode in the Configuration object. Always use / (slash) to separate path components, never \ (backslash). If you are loading templates from your local file system and it uses backslashes (like under. Windows), FreeMarker will convert them automatically. Example: Assume /common/copyright.ftl contains: Copyright 2001-2002 ${me}<br> All rights reserved. Then this: <#assign me = "Juila Smith"> <h1>Some test</h1> <p>Yeah. <hr> <#include "/common/copyright.ftl"> will output this: <h1>Some test</h1> <p>Yeah. <hr> Copyright 2001-2002 Juila Smith All rights reserved. The supported options are: parse: If it is true, then the included file will be parsed as FTL, otherwise the whole file will be considered as simple text (i.e, no FreeMarker constructs will be searched in it). If you omit this option, then it defaults to true. encoding: The included file inherits the encoding (in practice: the charset) of the including template, unless you specify an encoding with this option. Encoding names are the same as the ones supported be java.io.InputStreamReader (as of Java API 1.3: MIME-preferred charset names from the IANA Charset Registry). Examples of valid names: ISO-8859-2, UTF-8, Shift_JIS, Big5, EUC-KR, GB2312. Example: <#include "/common/navbar.html" parse=false encoding="Shift_JIS"> Note, that it is possible to automatically do the commonly used inclusions for all templates, with the "auto includes" setting of Configuration.
Using acquisition acquisition There's a special path component represented by an asterisk (*). It is interpreted as "this directory or any of its parents". Therefore, if the template located in /foo/bar/template.ftl has the following line: <#include "*/footer.ftl"> then the engine will look for the template in following locations, in this order: /foo/bar/footer.ftl /foo/footer.ftl /footer.ftl This mechanism is called acquisition and allows the designers to place commonly included files in a parent directory, and redefine them on a per-subdirectory basis as needed. We say that the including template acquires the template to include from the first parent directory that has it. Note that you can specify not only a template name to the right of the asterisk, but a subpath as well. I.e. if the previous template instead read: <#include "*/commons/footer.ftl"> then the engine would look for the template in following locations, in this order: /foo/bar/commons/footer.ftl /foo/commons/footer.ftl /commons/footer.ftl Finally, the asterisk needn't be the first element of the path: <#include "commons/*/footer.ftl"> would cause the engine to look for the template in following locations, in this order: /foo/bar/commons/footer.ftl /foo/bar/footer.ftl /foo/footer.ftl /footer.ftl However, there can be at most one asterisk in the path. Specifying more than one asterisk will result in a template not being found.
Localized lookup localization Whenever a template is loaded, it is assigned a locale. A locale is a language and an optional country or dialect identifier. A template is typically loaded by some code that the programmer wrote and he chooses a locale for the template based on some aspect. For example, when the FreemarkerServlet loads templates, it always requests the template with locale matching the language preference of the browser that requested the web page. When a template includes another template, it attempts to load a template with the same locale. Suppose your template was loaded with locale en_US, which means U.S. English. When you include another template: <include "footer.ftl"> the engine will in fact look for several templates, in this order: footer_en_US.ftl, footer_en.ftl, and finally footer.ftl Note that you can disable localized lookup feature with the setLocalizedLookup method of Configuration. When you use both acquisition and localized template lookup, the template with more specific locale in a parent directory takes precedence over template with less specific locale in a child directory. Suppose you use the following include from /foo/bar/template.ftl: <#include "*/footer.ftl"> the engine will look for these templates, in this order: /foo/bar/footer_en_US.ftl /foo/footer_en_US.ftl /footer_en_US.ftl /foo/bar/footer_en.ftl /foo/footer_en.ftl /footer_en.ftl /foo/bar/footer.ftl /foo/footer.ftl /footer.ftl
import import directive
Synopsis <#import path as hash> Where: path: The path of a template. This is an expression that evaluates to a string. (With other words, it doesn't have to be a fixed string, it can also be something like, for example, profile.baseDir + "/menu.ftl".) hash: The unquoted name of hash variable by which you can access the namespace. Not an expression.
Description Imports a library. That is, it creates a new empty namespace, and then executes the template given with path parameter in that namespace so the template populates the namespace with variables (macros, functions, ...etc.). Then it makes the newly created namespace available to the caller with a hash variable. The hash variable will be created as a plain variable in the namespace used by the caller of import (as if you would create it with assign directive), with the name given with the hash parameter. If you call import with the same path for multiple times, it will create the namespace and run the template for the very first call of import only. The later calls will just create a hash by which you can access the same namespace. The output printed by the imported template will be ignored (will not be inserted at the place of importing). The template is executed to populate the namespace with variables, and not to write to the output. Example: <#import "/libs/mylib.ftl" as my> <@my.copyright date="1999-2002"/> The path parameter can be a relative path like "foo.ftl" and "../foo.ftl", or an absolute like "/foo.ftl". Relative paths are relative to the directory of the template that uses the import directive. Absolute paths are relative to a base (often referred as the ''root directory of the templates'') that the programmer defines when he configures FreeMarker. Always use / (slash) to separate path components, never \ (backslash). If you are loading templates from your local file system and it uses backslashes (like under. Windows), FreeMarker will convert them automatically. Like with the include directive, acquisition and localized lookup may be used for resolving the path. Note, that it is possible to automatically do the commonly used imports for all templates, with the "auto imports" setting of Configuration. If you are new to namespaces, you should read:
noparse noparse directive
Synopsis <#noparse> ... </#noparse>
Description FreeMarker will not search FTL tags and interpolations and other special character sequences in the body of this directive, except the noparse end-tag. Example: Example: -------- <#noparse> <#list animals as being> <tr><td>${being.name}<td>${being.price} Euros </#list> </#noparse> will output: Example: -------- <#list animals as being> <tr><td>${being.name}<td>${being.price} Euros </#list>
compress compress directive white-space removal compress
Synopsis <#compress> ... </#compress>
Description The compress directive is useful for removing superfluous white-space when you use a white-space insensitive format (e.g. HTML or XML). It captures the output generated inside its body (i.e. between its start-tag and end-tag), and reduces all unbroken white-space sequences to a single white-space character. The inserted character will be a line break if the replaced sequence contains line breaks, or a space otherwise. The very first and very last unbroken white-space sequences will be completely removed. <#assign x = " moo \n\n "> (<#compress> 1 2 3 4 5 ${moo} test only I said, test only </#compress>) will output: (1 2 3 4 5 moo test only I said, test only)
escape, noescape escape directive noescape directive
Synopsis <#escape identifier as expression> ... <#noescape>...</#noescape> ... </#escape>
Description When you surround a part of the template with an escape directive, interpolations (${...}) that occur inside the block are combined with the escaping expression automatically. This is a convenience method for avoiding writing similar expressions all over. It does not affect interpolations in string literals (as in <#assign x = "Hello ${user}!">). Also, it does not affect numerical interpolations (#{...}). Example: <#escape x as x?html> First name: ${firstName} Last name: ${lastName} Maiden name: ${maidenName} </#escape> is actually equivalent to: First name: ${firstName?html} Last name: ${lastName?html} Maiden name: ${maidenName?html} Note that it is irrelevant what identifier you use in the directive - it just serves as a formal parameter to the escaping expression. When you are calling macros or the include directive, it is important to understand that escape has effect only on interpolations that occur between the <#escape ...> and </#escape> in the template text. That is, it will not escape anything that is before <#escape ...> in the text, or after the </#escape> in the text, not even if that part is called from inside the escape-d section. <#assign x = "<test>"> <#macro m1> m1: ${x} </#macro> <#escape x as x?html> <#macro m2>m2: ${x}</#macro> ${x} <@m1/> </#escape> ${x} <@m2/> the output will be: &lt;test&gt; m1: <test> <test> m2: &lt;test&gt; More technically, the effects of escape directive are applied at template parsing time rather than at template processing time. This means that if you call a macro or include another template from within an escape block, it won't affect the interpolations in the macro/included template, since macro calls and template includes are evaluated at template processing time. On the other hand, if you surround one or more macro declarations (which are evaluated at template parsing time, as opposed to macro calls) with an escape block, the interpolations in those macros will be combined with the escaping expression. Sometimes there is a need to temporarily turn off escaping for one or two interpolations in an escape block. You can achieve this by closing and later reopening the escape block, but then you have to write the escaping expression twice. You can instead use the noescape directive: <#escape x as x?html> From: ${mailMessage.From} Subject: ${mailMessage.Subject} <#noescape>Message: ${mailMessage.htmlFormattedBody}</#noescape> ... </#escape> is equivalent to: From: ${mailMessage.From?html} Subject: ${mailMessage.Subject?html} Message: ${mailMessage.htmlFormattedBody} ... Escapes can be nested (although you will do it only in rare circumstances). Therefore, you can write something like the below code (the example is admittedly a bit stretched, as you'd probably place item codes in a sequence and use list to iterate over them, but we're now doing it this way just to illustrate the point): <#escape x as x?html> Customer Name: ${customerName} Items to ship: <#escape x as itemCodeToNameMap[x]> ${itemCode1} ${itemCode2} ${itemCode3} ${itemCode4} </#escape> </#escape> is actually equivalent to: Customer Name: ${customerName?html} Items to ship: ${itemCodeToNameMap[itemCode1]?html} ${itemCodeToNameMap[itemCode2]?html} ${itemCodeToNameMap[itemCode3]?html} ${itemCodeToNameMap[itemCode4]?html} When you use the noescape directive in a nested escape block, it undoes only a single level of escaping. Therefore, to completely turn off escaping in a two-level deep escaped block, you need to use two nested noescape directives as well.
assign assign directive
Synopsis <#assign name=value> or <#assign name1=value1 name2=value2 ... nameN=valueN> or <#assign same as above... in namespacehash> or <#assign name> capture this </#assign> or <#assign name in namespacehash> capture this </#assign> Where: name: name of the variable. It is not expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#assign "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}"). value: the value to store. Expression. namespacehash: a hash that was created for a namespace (by import). Expression.
Description With this you can create a new variable, or replace an existing variable. Note that only top-level variables can be created/replaced (i.e. you can't create/replace some_hash.subvar, but some_hash). For more information about variables, read this: Example: variable seasons will store a sequence: <#assign seasons = ["winter", "spring", "summer", "autumn"]> Example: Increments the numerical value stored in variable test: <#assign test = test + 1> As a convenience feature, you can do more assignments with one assign tag. For example this will do the same as the two previous examples: <#assign seasons = ["winter", "spring", "summer", "autumn"] test = test + 1 > If you know what namespaces are: assign directive creates variables in namespaces. Normally it creates the variable in the current namespace (i.e. in the namespace associated with the template where the tag is). However, if you use in namespacehash then you can create/replace a variable of another namespace than the current namespace. For example, here you create/replace variable bgColor of the namespace used for /mylib.ftl: <#import "/mylib.ftl" as my> <#assign bgColor="red" in my> An extreme usage of assign is when it captures the output generated between its start-tag and end-tag. That is, things that are printed between the tags will not be shown on the page, but will be stored in the variable. For example: <#macro myMacro>foo</#macro> <#assign x> <#list 1..3 as n> ${n} <@myMacro /> </#list> </#assign> Number of words: ${x?word_list?size} ${x} will print: Number of words: 6 1 foo 2 foo 3 foo Please note that you should not to use this to insert variables into strings: <#assign x>Hello ${user}!</#assign> <#-- BAD PRACTICE! --> You should simply write: <#assign x="Hello ${user}!">
global global directive
Synopsis <#global name=value> or <#global name1=value1 name2=value2 ... nameN=valueN> or <#global name> capture this </#global> Where: name: name of the variable. It is not expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#global "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}"). value: the value to store. Expression.
Description This directive is similar to assign, but the variable created will be visible in all namespaces, and will not be inside any namespace. Exactly as if you would create (or replace) a variable of the data-model. Hence, the variable is global. If a variable with the same name already exists in the data-model, it will be hidden by the variable created with this directive. If a variable with the same name already exists in the current namespace, that will hide the variable created with global directive. For example, with <#global x = 1> you create a variable that is visible as x in all namespaces, unless another variable called x hides it (for example a variable what you have created as <#assign x = 2>). In this case, you can use special variable globals, like ${.globals.x}. Note that with globals you see all globally accessible variables; not only the variables that were created with global directive, but also the variables of the data-model. Note for custom JSP tag users: The set of variables created with this directive corresponds to the JSP page-scope. This means, that if a custom JSP tag wants to get a page-scope attribute (page-scope bean), a variable with the same name in the current namespace will not hide it from the viewpoint of the JSP tag.
local local directive
Synopsis <#local name=value> or <#local name1=value1 name2=value2 ... nameN=valueN> or <#local name> capture this </#local> Where: name: the name of the local object in the root. It is not an expression. However, it can be written as a string literal, which is useful if the variable name contains reserved characters, for example <#local "foo-bar" = 1>. Note that this string literal does not expand interpolations (as "${foo}"). value: the value to store. Expression.
Description It is similar to assign directive, but it creates or replaces local variables. This only works inside macro definitions and function definitons. For more information about variables, read this:
setting setting directive
Synopsis <#setting name=value> Where: name: name of the setting. It is not expression! value: New value of the setting. Expression
Description Sets a setting for the further part of processing. Settings are values that influence the behavior of FreeMarker. The new value will be present only in the template processing where it was set, and does not touch the template itself. The initial value of settings is set by the programmer (see: ). The supported settings are: locale locale: The locale (language) of the output. It can influence the presentation format of numbers, dates, etc. The value is a string which consist of a language code (lowercase two-letter ISO-639 code) plus optional county code (uppercase two-letter ISO-3166 code) separated from the language code with underscore, and if we have specified the country then an optional variant code (not standardized) separated from the country with underscore. Examples of valid values: en, en_US, en_US_MAC. FreeMarker will try to use the most specific available locale, so if you specify en_US_MAC but that is not known, then it will try en_US, and then en, and then the default locale of the computer (which is may set by the programmer). number_format format number number_format: The number format that is used to convert numbers to strings when no explicit format is specified. Can be one of predefined values number (the default), computer, currency, or percent. Additionally, arbitrary format pattern written in Java decimal number format syntax can also be specified. More information about format patterns:string built-in. boolean_format format boolean boolean_format: The comma-separated pair of strings for representing true and false values respectively that is used to convert booleans to strings when no explicit format is specified. Default value is "true,false". See also:string built-in. date_format time_format datetime_format format date date_format, time_format, datetime_format: The date/time format used to convert dates to strings when no explicit format is specified, as in the case of ${someDate}. date_format affects only the formatting of date-only dates (year, month, day), time_format affects only the formatting of time-only dates (hour,minute, second, millisecond), datetime_format affects only the formatting of date-time dates (year, month, day, hour, minute, second, millisecond). The possible values of the settings are similar to the parameters of string built-in of dates; see more explanation there. Examples: "short", "long_medium", "MM/dd/yyyy". time_zone time_zone: The name of the time zone used to format times for display. By default, the system time zone is used. Can be any value that is accepted by Java TimeZone API. Examples: "GMT", "GMT+2", "GMT-1:30", "CET", "PST", "America/Los_Angeles" url_escaping_charset url_escaping_charset: The charset used for URL escaping (e.g. for ${foo?url}) to calculate the escaped (%XX) parts. Usually the framework that encloses FreeMarker should set it, so you hardly ever should set this setting in templates. (Programmers can read more about this here...) classic_compatible classic_compatible: This is for experts. Its value should be a boolean. See the documentation of freemarker.template.Configurable for more information. Example: Assume that the initial locale of template is hu (Hungarian). Then this: ${1.2} <#setting locale="en_US"> ${1.2} will output this: 1,2 1.2 because Hungarian people use the comma as their decimal separator, while US people use the dot.
User-defined directive (<@...>) user-defined directive
Synopsis <@user_def_dir_exp param1=val1 param2=val2 ... paramN=valN/> (Note the XML-style / before the >) or if you need loop variables (more details...) <@user_def_dir_exp param1=val1 param2=val2 ... paramN=valN ; lv1, lv2, ..., lvN/> Or the same as the above two but with end-tag (more details...): <@user_def_dir_exp ...> ... </@user_def_dir_exp> or <@user_def_dir_exp ...> ... </@> Or all above but with positional parameter passing (more details...): <@user val1, val2, ..., valN/> ...etc. Where: user_def_dir_exp: Expression evaluates to an user-defined directive (for example a macro), that will be called. param1, param2, ...etc.: The name of parameters. They are not expressions. val1, val2, ...etc.: The value of parameters. They are expressions. lv1, lv2, ...etc.: The name of loop variables. They are not expressions. The number of parameters can be 0 (i.e. no parameters). The order of parameters is not significant (unless you use positional parameter passing). The name of parameters must be unique. Lower- and uppercase letters are considered as different letters in parameter names (i.e. Color and color is not the same).
Description This will call an user-defined directive, for example a macro. The meaning of parameters, and the set of supported and required parameters depend on the concrete user-defined directive. You may read the tutorial about user-defined directives. Example 1: Calls the directive that is stored in the variable html_escape: <@html_escape> a < b Romeo & Juliet </@html_escape> Output: a &lt; b Romeo &amp; Juliet Example 2: Calls a macro with parameters: <@list items=["mouse", "elephant", "python"] title="Animals"/> ... <#macro list title items> <p>${title?cap_first}: <ul> <#list items as x> <li>${x?cap_first} </#list> </ul> </#macro> Output: <p>Animals: <ul> <li>Mouse <li>Elephant <li>Python </ul> ...
End-tag You can omit the user_def_dir_exp in the end-tag. That is, you can always write </@> instead of </@anything>. This rule is mostly useful when the user_def_dir_exp expression is too complex, because you don't have to repeat the expression in the end-tag. Furthermore, if the expression contains other than simple variable names and dots, you are not allowed to repeat the expression. For example, <@a_hash[a_method()]>...</@a_hash[a_method()]> is an error; you must write <@a_hash[a_method()]>...</@>. But <@a_hash.foo>...</@a_hash.foo> is OK.
Loop variables Some user-defined directives create loop variables (similarly to list directive). As with the predefined directives (as list) the name of loop variables is given when you call the directive (as foo in <#list foos as foo>...</#list>), while the value of the variable is set by the directive itself. In the case of user-defined directives the syntax is that the name of loop variables is given after a semicolon. For example: <@myRepeatMacro count=4 ; x, last> ${x}. Something... <#if last> This was the last!</#if> </@myRepeatMacro> Note that the number of loop variable created by the user-defined directive and the number of loop variables specified after the semicolon need not match. Say, if you are not interested if the repetition is the last, you can simply write: <@myRepeatMacro count=4 ; x> ${x}. Something... </@myRepeatMacro> or you can even: <@myRepeatMacro count=4> Something... </@myRepeatMacro> Furthermore, it does not cause error if you specify more loop variables after the semicolon than the user-defined directive creates, just the last few loop variables will not be created (i.e. those will be undefined in the nested content). Trying to use the undefined loop variables, however, will cause error (unless you use built-ins like ?default), since you try to access a non-existing variable. See the the tutorial about user-defined directives for more explanation.
Positional parameter passing positional parameter passing Positional parameter passing (as <@heading "Preface", 1/>) is a shorthand form of normal named parameter passing (as <@heading title="Preface" level=1/>), where you omit the parameter name. This shorthand form should be used if a user-defined directive has only one parameter, or if it is easy to remember the order of parameters for a frequently used user-defined directive. To use this form, you have to know the order in which the named parameters are declared (trivial if the directive has only one parameter). Say, if heading was created as <#macro heading title level>..., then <@heading "Preface", 1/> is equivalent with <@heading title="Preface" level=1/> (or <@heading level=1 title="Preface"/>; if you use parameter names, the order is not important). Note that positional parameter passing is currently only supported for macros.
macro, nested, return macro directive nested directive return directive
Synopsis <#macro name param1 param2 ... paramN> ... <#nested loopvar1, loopvar2, ..., loopvarN> ... <#return> ... </#macro> Where: name: name of macro variable. It's not an expression. However, it can be written as a string literal, which is useful if the macro name contains reserved characters, for example <#macro "foo-bar">.... Note that this string literal does not expand interpolations (as "${foo}"). param1, param2, ...etc.: the name of the local variables store the parameter values (not expression), optionally followed by = and the default value (that's an expression). The default value can even be another parameter, for example <#macro section title label=title>. paramN, the last parameter, may optionally include a trailing ellipsis (...), which indicates the macro takes a variable number of parameters. If called using named parameters, paramN will be a hash containing all of the undeclared key/value pairs passed to the macro. If called using positional parameters, paramN will be a sequence of the extra parameters. loopvar1, loopvar2, ...etc.: Optional. The values of loop variables that the nested directive wants to create for the nested content. These are expressions. The return and nested directives are optional and can be used anywhere and for any times between the <#macro ...> and </#macro>. Parameters without default value must precede parameters with default value (paramName=defaultValue).
Description Creates a macro variable (in the current namespace, if you know namespace feature). If you are new to macros and user-defined directives you should read the the tutorial about user-defined directives. Macro variable stores a template fragment (called macro definition body) that can be used as user-defined directive. The variable also stores the name of allowed parameters to the user-defined directive. You must give value for all of those parameters when you use the variable as directive, except for parameters that has a default value. The default value will be used if and only if you don't give value for the parameter when you call the macro. The variable will be created at the beginning of the template; it does not mater where the macro directive is placed in the template. Thus, this will work: <#-- call the macro; the macro variable is already created: --> <@test/> ... <#-- create the macro variable: --> <#macro test> Test text </#macro> However, if the macro definitions are inserted with include directive, they will not be available until FreeMarker has executed the include directive. Example: Macro without parameters: <#macro test> Test text </#macro> <#-- call the macro: --> <@test/> Output: Test text Example: Macro with parameters: <#macro test foo bar baaz> Test text, and the params: ${foo}, ${bar}, ${baaz} </#macro> <#-- call the macro: --> <@test foo="a" bar="b" baaz=5*5-2/> Output: Test text, and the params: a, b, 23 Example: Macro with parameters and default parameter values: <#macro test foo bar="Bar" baaz=-1> Test text, and the params: ${foo}, ${bar}, ${baaz} </#macro> <@test foo="a" bar="b" baaz=5*5-2/> <@test foo="a" bar="b"/> <@test foo="a" baaz=5*5-2/> <@test foo="a"/> Output: Test text, and the params: a, b, 23 Test text, and the params: a, b, -1 Test text, and the params: a, Bar, 23 Test text, and the params: a, Bar, -1 Example: A more complex macro. <#macro list title items> <p>${title?cap_first}: <ul> <#list items as x> <li>${x?cap_first} </#list> </ul> </#macro> <@list items=["mouse", "elephant", "python"] title="Animals"/> Output: <p>Animals: <ul> <li>Mouse <li>Elephant <li>Python </ul> Example: A macro with support for a variable number of named parameters: <#macro img src extra...> <img src="/context${src?html}" <#list extra?keys as attr> ${attr}="${extra[attr]?html}" </#list> > </#macro> <@img src="/images/test.png" width=100 height=50 alt="Test"/> Output: <img src="/context/images/test.png" alt="Test" height="50" width="100" >
nested The nested directive executes the template fragment between the start-tag and end-tags of the user-defined directive. The nested part can contain anything what is valid in templates; interpolations, directives, ...etc. It is executed in the context where the macro was called from, rather than in the context of the macro definition body. Thus, for example, you don't see the local variables of the macro in the nested part. If you don't call the nested directive, the part between the start-tag and end-tags of the user-defined directive will be ignored. Example: <#macro do_twice> 1. <#nested> 2. <#nested> </#macro> <@do_twice>something</@do_twice> Output: 1. something 2. something The nested directive can create loop variables for the nested content. For example: <#macro do_thrice> <#nested 1> <#nested 2> <#nested 3> </#macro> <@do_thrice ; x> ${x} Anything. </@do_thrice> This will print: 1 Anything. 2 Anything. 3 Anything. A more complex example: <#macro repeat count> <#list 1..count as x> <#nested x, x/2, x==count> </#list> </#macro> <@repeat count=4 ; c, halfc, last> ${c}. ${halfc}<#if last> Last!</#if> </@repeat> The output will be: 1. 0.5 2. 1 3. 1.5 4. 2 Last!
return With the return directive, you can leave a macro or function definition body anywhere. Example: <#macro test> Test text <#return> Will not be printed. </#macro> <@test/> Output: Test text
function, return function directive return directive method defining with FTL
Synopsis <#function name param1 param2 ... paramN> ... <#return returnValue> ... </#function> Where: name: name of method variable (not expression) param1, param2, ...etc.: the name of the local variables store the parameter values (not expression), optionally followed by = and the default value (that's an expression). paramN, the last parameter, may optionally include a trailing ellipsis (...), which indicates the macro takes a variable number of parameters. Local variable paramN will be a sequence of the extra parameters. returnValue: the expression that calculates the value of the method call. The return directive can be used anywhere and for any times between the <#function ...> and </#function>. Parameters without default value must precede parameters with default value (paramName=defaultValue).
Description Creates a method variable (in the current namespace, if you know namespace feature). This directive works in the same way as the macro directive, except that return directive must have a parameter that specifies the return value of the method, and that attempts to write to the output will be ignored. If the </#function> is reached (i.e. there was no return returnValue), then the return value of the method is an undefined variable. Example 1: Creating a method that calculates the average of two numbers: <#function avg x y> <#return (x + y) / 2> </#function> ${avg(10, 20)} will print: 15 Example 2: Creating a method that calculates the average of multiple numbers: <#function avg nums...> <#local sum = 0> <#list nums as num> <#local sum = sum + num> </#list> <#if nums?size != 0> <#return sum / nums?size> </#if> </#function> ${avg(10, 20)} ${avg(10, 20, 30, 40)} ${avg()!"N/A"} will print: 15 25 N/A
flush flush directive
Synopsis <#flush>
Description When FreeMarker generates the output it typically stockpiles the generated output and send it to the client in one or in a few big pieces. This act of sending is called flushing (as flushing the toilet). Although flushing happens automatically, sometimes you want to force it on certain points of the template processing, and this is what flush directive does. If it is needed, then the programmer could tell it to you; typically you should not use this directive. The mechanism of automatic flushing and the precise effect of flush directive are under the control of the programmer. Flush simply calls the flush method of the currently used java.io.Writer instance. The whole buffering and flushing mechanism is implemented in the writer (what you have passed as the parameter of the Template.process method); FreeMarker does not deal with it.
stop stop directive
Synopsis <#stop> or <#stop reason> Where: reason: Informative message about the reason of termination. Expression evaluates to string.
Description Aborts the processing of template. This is something like an emergency brake: don't use it in normal situations. Aborting happens by throwing a StopException, and the StopException will hold the value of reason parameter.
ftl ftl directive header charset encoding white-space removal stripping
Synopsis <#ftl param1=value1 param2=value2 ... paramN=valueN> Where: param1, param2, ...etc.: Name of the parameter. Not an expression. Allowed parameters are: encoding, strip_whitespace, strip_text, ...etc. See below. value1, value2, ...etc.: The value of parameter. This must be a constant expression (as true, or "ISO-8859-5", or {x:1, y:2}). It can't use variables.
Description Tells information about the template for FreeMarker and for other tools, also helps programs to automatically detect if a text file is an FTL file. This directive, if present, must be the very first thing in the template. Any white-space before this directive will be ignored. The old-syntax (#-less) format of this directive is not supported. The settings (encoding, white-space stripping, etc.) given here has the highest precedence, that is, they will be used for the template regardless of any FreeMarker configuration settings. Parameters: encoding: With this you can specify the encoding (charset) of the template in the template file itself. (That is, this will be the encoding setting of the newly created Template, and not even the encoding parameter to Configuration.getTemplate can override it). Note however, that FreeMarker will try to find and interpret the ftl directive first with the automatically guessed encoding (which depends on the FreeMarker configuration set by the programmers), and only then realizes if the ftl directive dictates something different, and re-read the template with the new encoding. Thus, the template must be valid FTL until the end of ftl tag with the encoding tried first. The valid values of this parameter are MIME-preferred charset names from the IANA Charset Registry, like ISO-8859-5, UTF-8 or Shift_JIS. strip_whitespace: This enables/disables white-space stripping. Valid values are the boolean constants true and false. (And for backward compatibility, strings "yes", "no", "true", "false"). The default value (i.e. when you don't use this parameter) depends on the FreeMarker configuration set by the programmers, but it should be true for new projects. strip_text: When enabled, all top-level text in a template is removed when the template is parsed. This does not affect text within macros, directives, or interpolations. Valid values are the boolean constants true and false. (And for backward compatibility, strings "yes", "no", "true", "false"). The default value (i.e. when you don't use this parameter) is false. strict_syntax: This turns on/off ``strict syntax''. Valid values are the boolean constants true and false. (And for backward compatibility, strings "yes", "no", "true", "false"). The default value (i.e. when you don't use this parameter) depends on the FreeMarker configuration set by the programmers, but it should be true for new projects. (Programmers: you must set explicitly this setting to true for this: config.setStrictSyntaxMode(true);) For more information read: ns_prefixes: This is a hash that associates prefixes with node namespaces. For example: {"e":"http://example.com/ebook", "vg":"http://example.com/vektorGraphics"}. This is mostly used with XML processing where the prefixes can be used in XML queries, but it also influences the working of directives visit and recurse. Only one prefix can be registered for the same node namespace (otherwise an error will occur), so there is one-to-one relation between prefixes and node namespaces. Prefixes D and N are reserved. If you register prefix D, then other than you associate the node namespace with prefix D, you also set the default node namespace. Prefix N can't be registered; it is used to denote nodes with no node namespace in certain places, when (and only when) prefix D is registered. (To see the usage of default node namespace, N, and prefixes in general, see the part about XML processing and visit and recurse in the reference.) The effect of ns_prefixes is limited to a single FTL namespace, namely, to the FTL namespace that was created for the template. This also means that ns_prefixes has effect only when an FTL namespace is created for the template that contains it, otherwise the ns_prefixes parameter has no effect. An FTL namespace is made for a template when: (a) the template is the ``main'' template, that is, it is not invoked as a result of an <#include ...>, but it is directly invoked (with the process Java method of class Template or Environment); (b) the template is invoked directly with <#import ...>. attributes: This is a hash that associates arbitrary attributes (name-value pairs) to the template. The values of the attributes can be of any type (string, number, sequence... etc.). FreeMarker doesn't try to understand the meaning of the attributes. It's up to the application that encapsulates FreeMarker (as a Web application framework). Thus, the set of allowed attributes and their semantic is application (Web application framework) dependent. Programmers: you can get the attributes associated with a Template object with its getCustomAttributeNames and getCustomAttribute methods (inherited from freemarker.core.Configurable). As the template attributes are associated with the Template object when the template is parsed, the attributes can be read anytime, the template need not be executed. The methods mentioned return the attribute values unwrapped, that is, with FreeMarker independent type as java.util.List. This directive also determines if the template uses angle bracket syntax (e.g. <#include 'foo.ftl'>) or square bracket syntax (e.g. [#include 'foo.ftl']). Simply, the syntax used for this directive will be the syntax used for the whole template, regardless of the FreeMarker configuration settings.
t, lt, rt t directive lt directive rt directive trimmer directives white-space removal trimming
Synopsis <#t> <#lt> <#rt> <#nt>
Description These directives, instruct FreeMarker to ignore certain white-space in the line of the tag: t (for trim): Ignore all leading and trailing white-space in this line. lt (for left trim): Ignore all leading white-space in this line. rt (for right trim): Ignore all trailing white-space in this line. where: ``leading white-space'' means all space and tab (and other character that are white-space according to UNICODE, except line breaks) before the first non-white-space character of the line. ``trailing white-space'' means all space and tab (and other character that are white-space according to UNICODE, except line breaks) after the last non-white-space character of the line, and the line break at the end of the line. It is important to understand that these directives examine the template itself, and not the output what the template generates when you merge it with the data-model. (That is, the white-space removal happens on parse time.) For example this: -- 1 <#t> 2<#t> 3<#lt> 4 5<#rt> 6 -- will output this: -- 1 23 4 5 6 -- The placement of these directives inside the line has no importance. That is, the effect will be the same regardless if you put the directive at the beginning of the line, or at the end of the line, or in the middle of the line.
nt nt directive trimmer directives white-space removal trimming white-space removal stripping
Synopsis <#nt>
Description ``No Trim''. This directive disables white-space stripping in the line where it occurs. It also disables the effect of other trim directives occuring in the same line (the effect of t, rt, lt).
attempt, recover attempt directive recover directive error handling
Synopsis <#attempt> attempt block <#recover> recover block </#attempt> Where: attempt block: Template block with any content. This will be always executed, but if an error occurs during that, all output from this block is rolled back, and the recover block will be executed. recover block: Template block with any content. This will be executed only if there was an error during the execution of the attempt block. You may print an error messages here and such. The recover is mandatory. attempt/recover can be nested freely into other attempt blocks or recover blocks. The format shown here is supported starting from 2.3.3; earlier it was <#attempt>...<#recover>...</#recover>, which is still supported for backward compatibility. Furthermore, these directives were introduced with FreeMarker 2.3.1, so they aren't exist in 2.3.
Description These directives are used if you want the page successfully outputted even if the outputting of a certain part of the page fails. If an error occurs during the execution of the attempt block, then the template execution is not aborted, but the recover block is executed instead of the attempt block. If no error occurs during the execution of the attempt block, then the recover block is ignored. A simple example: Primary content <#attempt> Optional content: ${thisMayFails} <#recover> Ops! The optional content is not available. </#attempt> Primary content continued If the thisMayFails variable doesn't exist, then the output is: Primary content Ops! The optional content is not available. Primary content continued If the thisMayFails variable exists and it's value is 123, then the output is: Primary content Optional content: 123 Primary content continued The attempt block has an all-or-none semantic: either the entire content of the attempt block is output (when there was no error), or no output at all results from the execution of the attempt block (when there was an error). For example, above, the failure happens after ``Optional content: '' was printed, still it is not there in the output before the ``Ops!''. (This is implemented with the aggressive buffering of the output inside the attempt block. Not even the flush directive will send the output to the client.) To prevent misunderstandings coming from the above example: attempt/recover is not (only) for handling undefined variables (for that use missing value handler operators). It can handle all kind of errors that occurs when the block is executed (i.e. not syntactical errors, which are detected earlier). And it's meant to enclose bigger template fragments, where error can occur at various points. For example, you have a part in your template that deals with printing advertisements, but that's not the primary content of the page, so you don't want your whole page be down just because some error occurs with the printing of the advertisements (say, because of a temporal database server faliure). So you put the whole advertisement printing into an attempt block. In some environments programmers configure FreeMarker so that it doesn't abort template execution for certain errors, but continues execution, possibly after printing some error indicator to the output (see more here...). The attempt directive doesn't consider such suppressed errors as errors. Inside a recover block the error message of the error is available with the error special variable. Don't forget that references to special variable are started with dot (for example: ${.error}). Errors occurring during template execution are always logged, even if they occur inside an attempt block.
visit, recurse, fallback visit directive recurse directive fallback directive recursion iterate
Synopsis <#visit node using namespace> or <#visit node> <#recurse node using namespace> or <#recurse node> or <#recurse using namespace> or <#recurse> <#fallback> Where: node: Expression evaluates to a node variable. namespace: A namespace, or a sequence of namespaces. A namespace can be given with the namespace hash (a.k.a. gate hash), or with a string literal that store the path of template that could be imported. Instead of namespace hashes, you can use plain hashes as well.
Description The visit and recurse directives are used for the recursive processing of trees. In practice, this will mostly be used for processing XML.
Visit When you call <#visit node>, it looks for a user-defined directive (like a macro) to invoke that has the name deducted from the node's name (node?node_name) and namespace (node?node_namesoace). The rules of name deduction: If the node doesn't support node namespaces (as text nodes in XML), then the directive name is simply the name of the node (node?node_name). A node does not support node namespaces if the getNodeNamespace method returns null. If the node does support node namespaces (as element nodes in XML), then a prefix deduced from the node namespace maybe appended before the node name with a colon used as separator (e.g. e:book). The prefix, and if there is a prefix used at all, depends on what prefixes has been registered with the ns_prefixes parameter of the ftl directive in the FTL namespace where visit looks for the handler directive (which is not necessary the same as the FTL namespace where visit was called from, as you will see later). Concretely, if there was no default namespace registered with ns_prefixes then for nodes that does not belong to any namespace (when getNodeNamespace returns "") no prefix is used. If there was a default namespace registered with ns_prefixes then for nodes that does not belong to any namespace prefix N is used, and for nodes that belong to the default node namespace no prefix is used. Otherwise, in both case, the prefix associated to the node namespace with the ns_prefixes is used. If there is not prefix associated to the node namespace of the node, then visit simply behave as if there was no directive found with the proper name. The node for which the user-defined directive was invoked is available for it as special variable .node. Example: <#-- Assume that nodeWithNameX?node_name is "x" --> <#visit nodeWithNameX> Done. <#macro x> Now I'm handling a node that has the name "x". Just to show how to access this node: this node has ${.node?children?size} children. </#macro> The output will be something like: Now I'm handling a node that has the name "x". Just to show how to access this node: this node has 3 children. Done. If one or more namespaces is specified using the optional using clause, then visit will look for the directives in those namespaces only, with the earlier specified namespaces in the list getting priority. If no using clause is specified, the namespace or sequence of namespaces specified with the using clause of the last uncompleted visit call is reused. If there is no such pending visit call, then the current namespace is used. For example, if you execute this template: <#import "n1.ftl" as n1> <#import "n2.ftl" as n2> <#-- This will call n2.x (because there is no n1.x): --> <#visit nodeWithNameX using [n1, n2]> <#-- This will call the x of the current namespace: --> <#visit nodeWithNameX> <#macro x> Simply x </#macro> and this is n1.ftl: <#macro y> n1.y </#macro> and this is n2.ftl: <#macro x> n2.x <#-- This will call n1.y, becuase it inherits the "using [n1, n2]" from the pending visit call: --> <#visit nodeWithNameY> <#-- This will call n2.y: --> <#visit nodeWithNameY using .namespace> </#macro> <#macro y> n2.y </#macro> then this will print: n2.x n1.y n2.y Simply x If visit doesn't find a user-defined directive in either FTL namespaces with the name identical to the name deduced with the rules described earlier, then it tries to find an user-defined directive with name @node_type, or if the node does not support node type property (i.e. node?node_type returns undefined variable), then with name @default. For the lookup, it uses the same mechanism as was explained earlier. If it still doesn't find an user-defined directive to handle the node, then visit stops template processing with error. Some XML specific node types have special handling in this regard; see: . Example: <#-- Assume that nodeWithNameX?node_name is "x" --> <#visit nodeWithNameX> <#-- Assume that nodeWithNameY?node_type is "foo" --> <#visit nodeWithNameY> <#macro x> Handling node x </#macro> <#macro @foo> There was no specific handler for node ${node?node_name} </#macro> This would print: Handling node x There was no specific handler for node y
Recurse The <#recurse> directive is really syntactic sugar. It visits all children nodes of the node (and not the node itself). So, to write: <#recurse someNode using someLib> is equivalent to writing: <#list someNode?children as child><#visit child using someLib></#list> However, target node is optional in the recurse directive. If the target node is unspecified, it simply uses the .node. Thus, the terse instruction <#recurse> is equivalent to: <#list .node?children as child><#visit child></#list> As a side comment for those who are familiar with XSLT, <#recurse> is pretty much exactly analogous to the <xsl:apply-templates/> instruction in XSLT.
Fallback As you could learn earlier, in the documentation of the visit directive, the user-defined directive that handles the node is maybe searched in multiple FTL name-spaces. The fallback directive can be used in a user-defined directive that was invoked to handle a node. It directs FreeMarker to continue the searching for the user-defined directive in the further name-spaces (that is, in the name-spaces that are after the name-space of the currently invoked user-defined directive in the list of name-spaces). If a handler for the node is found then it is invoked, otherwise fallback does nothing. A typical usage of this to write customization layer over a handler library, that sometimes passes the handling to the customized library: <#import "/lib/docbook.ftl" as docbook> <#-- We use the docbook library, but we override some handlers in this namespace. --> <#visit document using [.namespace, docbook]> <#-- Override the "programlisting" handler, but only in the case if its "role" attribute is "java" --> <#macro programlisting> <#if .node.@role[0]!"" == "java"> <#-- Do something special here... --> ... <#else> <#-- Just use the original (overidden) handler --> <#fallback> </#if> </#macro>
Special Variable Reference special variable Special variables are variables defined by the FreeMarker engine itself. To access them, you use the .variable_name syntax. For example, you can't write simply version; you have to write .version. The supported special variables are: data_model: A hash that you can use to access the data-model directly. That is, variables you did with global directive are not visible here. error error (available since FreeMarker 2.3.1): This variable accessible in the body of the recover directive, where it stores the error message of the error we recover from. globals: A hash that you can use to access the globally accessible variables: the data-model and the variables created with global directive. Note that variables created with assign or macro are not globals, thus they never hide the variables when you use globals. language lang lang: Returns the language part of the current value of the locale setting. For example if .locale is en_US, then .lang is en. locale locale: Returns the current value of the locale setting. This is a string, for example en_US. For more information about locale strings see the setting directive. locals: A hash that you can use to access the local variables (the variables created with the local directive, and the parameters of macro). main: A hash that you can use to access the main namespace. Note that global variables like the variables of data-model are not visible through this hash. namespace: A hash that you can use to access the current namespace. Note that global variables like the variables of data-model are not visible through this hash. node (alias current_node for historical reasons): The node you are currently processing with the visitor pattern (i.e. with the visit, recurse, ...etc. directives). Also, it initially stores the root node when you use the FreeMarker XML Ant task. now current date-time now: Returns the current date-time. Usage examples: "Page generated: ${.now}", "Today is ${.now?date}", "The current time is ${.now?time}". output encoding output charset output_encoding (available since FreeMarker 2.3.1): Returns the name of the current output charset. This special variable is not existent if the framework that encapsulates FreeMarker doesn't specify the output charset for FreeMarker. (Programmers can read more about charset issues here...) template_name: The name of the current template (available since FreeMarker 2.3.14). URL escaping charset URL escaping charset url_escaping_charset (available since FreeMarker 2.3.1): If exists, it stores the name of the charset that should be used for URL escaping. If this variable doesn't exist that means that nobody has specified what charset should be used for URL encoding yet. In this case the url built-in uses the charset specified by the output_encoding special variable for URL encoding; custom mechanism may follow the same logic. (Programmers can read more about charset issues here...) vars: Expression .vars.foo returns the same variable as expression foo. It's useful if for some reasons you have to use square bracket syntax, since that works only for hash subvariables, so you need an artificial parent hash. For example, to read a top-level variable that has a strange name that would confuse FreeMarker, you can write .vars["A strange name!"]. Or, to access a top-level variable with dynamic name given with variable varName you can write .vars[varName]. Note that the hash returned by .vars does not support ?keys and ?values. version version: Returns the FreeMarker version number as string, for example 2.2.8. This can be used to check which FreeMarker version does your application use, but note that this special variable does not exist prior to the 2.3-final or 2.2.8 versions. The version number of non-final releases contain abbreviation ``pre'' for ``preview'' (e.g. 2.3pre6), or abbrevation ``rc'' for ``release candidate''. Reserved names in FTL reserved name The following names cannot be used for top-level variables without square-bracket syntax (as .vars["in"]), since they are keywords in FTL: true: boolean value ``true'' false: boolean value ``false'' gt: comparison operator ``greater than'' gte: comparison operator ``greater than or equivalent'' lt: comparison operator ``less than'' lte: comparison operator ``less than or equivalent'' as: used by a few directives in: used by a few directives using: used by a few directives Deprecated FTL constructs deprecated
List of deprecated directives The following directives are deprecated, but still working: call: use user-defined directive call instead comment: This is the old format of <#--...-->. Anything between the <#comment> and </#comment> will be ignored. foreach: it is a synonym of the list directive with slightly different parameter syntax. The syntax is <#foreach item in sequence> that is equivalent with <#list sequence as item>. transform: use user-defined directive call instead The following directives are not working anymore: Legacy function: Originally function was used to define macros, and was deprecated in favor of the macro directive. As of FreeMarker 2.3, this directive is reintroduced with different meaning: it is used to define methods.
List of deprecated built-ins The following built-ins are deprecated, but still working: default built-in default: This was deprecated with the introduction of the default value operator. exp1?default(exp2) is near equivalent with exp1!exp2, and (exp1)?default(exp2) is near equivalent with with (exp1)!exp2. The only difference is that prior to FreeMarker 2.4, the default built-in has always evaluated exp2, while the default value operator only evaluates it when the default value is really needed. Starting from FreeMarker 2.4, however, the default built-in was improved, and behaves exactly like the default value operator. exists built-in exists: This was deprecated with the introduction of the missing value test operator. exp1?exists is equivalent with exp1??, also (exp1)?exists is equivalent with with (exp1)??. if_exists built-in if_exists: This was deprecated with the introduction of the default value operator. exp1?if_exists is similar to exp1!, and (exp1)?if_exists is similar to (exp1)!. The difference is that the default value with if_exists is not only empty string, empty sequence and empty hashs at the same time, but also boolean false and a transform that does nothing and ignores all parameters. web_safe built-in web_safe: the same as html
Old-style macro and call directives
Synopsis <#macro name(argName1, argName2, ... argNameN)> ... </#macro> <#call name(argValue1, argValue2, ... argValueN)> Where: name: name of the macro (not expression) argName1, argName2, ...etc.: the name of the local variables store the parameter values (not expression) argValue1, argValue2, ...etc.: expressions, the value of the parameters
Description This is the documentation of FreeMarker 2.1 macro and macro related directives. These are still working, but deprecated. You may want to read the FreeMarker 2.2+ references: macro, return, user-defined directive call A macro is a template fragment with an associated name. You can use that named fragment on multiple places in your template, so it helps in repetitive tasks. A macro can have parameters that influence the output generated when you use the macro. You define a macro with the macro directive, and then you can use the defined macro in the whole template. The macro directive itself does not write anything to the output, it just defines the macro. For example this will define a macro called warning: <#macro warning(message)> <div align=center> <table border=1 bgcolor=yellow width="80%"><tr><td align=center> <b>Warning!</b> <p>${message} </td></tr></table> </div> </#macro> The macro definition body (the section between the macro start-tag and end-tag) will be processed whenever you use the call directive with the name of the macro. For example this calls the macro called warning: <#call warning("Unplug the machine before opening the cover!")> and will write this to the output: <div align=center> <table border=1 bgcolor=yellow width="80%"><tr><td align=center> <b>Warning!</b> <p>Unplug the machine before opening the cover! </td></tr></table> </div> The parameters passed in as parameters to the call directive will be accessible in the macro definition body as local variables. When you call a macro, you must specify the same number of parameters as were specified in the macro definition. For example if this is the macro definition: <#macro test(a, b, c)>Nothing...</#macro> then these are valid macro calls: <#call test(1, 2, 3)> <#call test("one", 2 + x, [1234, 2341, 3412, 4123])> If a macro has no parameters, then you can omit the parentheses: <#macro test>mooo</#macro> <#call test> When you define a macro it will be available in the template, where you have defined it only. But probably you want to use the same macros in more templates. In this case you can store your macro definitions in a common file, and then include that file in all templates where you need those macros. It's fine to call a macro that's defined further down in the template (since macros are defined at parse time, not in process time). However, if the macro definitions are inserted with include directive, they will not be available until FreeMarker has executed the include directive. You can leave a macro definition body before the </#macro> tag with the return directive.
Transform directive transform directive
Synopsis <transform transVar> ... </transform> or <transform transVar name1=value1 name2=value2 ... nameN=valueN> ... </transform> Where: transVar: Expression evaluates to a transform name1, name2, ... nameN: Name of parameters. Literal value, not expression. value1, value2, ... valueN: Expressions evaluate to the values of parameters
Description This directive is still working, but deprecated. You may want to read about user-defined directive calls to see the replacement. Captures the output generated inside its body (i.e. between its start-tag and end-tag), and let the given transform modify it before it is written to the final output. Example: <p>A very simple HTML file: <pre> <transform html_escape> <html> <body> <p>Hello word! </body> </html> </transform> </pre> the output will be: <p>A very simple HTML file: <pre> &lt;html&gt; &lt;body&gt; &lt;p&gt;Hello word! &lt;/body&gt; &lt;/html&gt; </pre> Some transforms may take parameters. The name and meaning of parameters depends on the transform in question. For example here we give a parameter called ``var'': <#-- This transform stores the output in the variable x, rather than sending it to the output --> <transform capture_output var="x"> some test </transform> It is the task of the programmers to put the necessary transforms into the data-model. For the name and usage of accessible transforms ask the programmers. Initially there is a shared variable for most transforms in the freemarker.template.utility package. For more information see:
Old FTL syntax strict syntax old FTL syntax new FTL syntax With the old FTL syntax the # was not required (prior 2.1 not even allowed) in the FTL tags. For example, you could write this: <html> <head> <title>Welcome!</title> </head> <body> <h1>Welcome ${user}!</h1> <p>We have there animals: <ul> <list animals as being> <li>${being.name} for ${being.price} Euros </list> </ul> <include "common_footer.html"> </body> </html> While the #-less syntax was more natural for HTML authors, it had too many drawbacks, so finally we have decided to deprecate it. With the newer syntax (a.k.a ``strict syntax''), the # is strictly required. That is, things like <include "common_footer.html"> will go to the output as is, since they are not considered as FTL tags. Note that user-defined directives use @ instead of #. However, to give users time to prepare for this change, in FreeMarker 2.1 and 2.2 the usage of # is optional, unless the programmer enables strict syntax mode in the FreeMarker configuration by calling setStrictSyntaxMode(true) on Configuration. In fact, we strongly recommend this to programmers. Starting from some later release this setting will be initially set to true. Also, you can specify if you want to use strict syntax or old syntax in the template files with the ftl directive. The advantages of ``strict syntax'' over the legacy FTL syntax are: Since all <#...> and </#...> are reserved for FTL: We can introduce new directives without breaking backward compatibility. We can detect if you made a typo, i.e. <#inculde ...> is treated as parse-time error, rather than silently treated as simple text. It is easier for third-party tools to handle templates (e.g. do syntax highlighting), especially since they don't have to know about the new directives introduced with new releases. Templates are more readable, since it is easier to spot <#...> tags embedded into HTML or other markup. <# and </# is illegal XML (except in CDATA sections), and illegal in almost all other SGML applications, so they can't interfere with the tags used in the static text parts (e.g. if you have include element in the generated XML).
#{...}: Numerical interpolation #{...} Deprecated: Use the number_format setting and the string built-in instead. For formatting for computer audience (i.e., no localized formatting) use the c built-in (like number?c).
Synopsis #{expression} or #{expression; format} Where: expression: expression that can be evaluated as a number. format: optional format specifier.
Description The numerical interpolation is used to output a number value. If the expression doesn't evaluate to a number, the evaluation ends with an error. The optional format specifier specifies the minimum and the maximum number of displayed fractional digits using syntax mminMmax. For example, m2M5 means "at least two, at most five fractional digits". The minimum or the maximum specifier part can be omitted. If only the minimum is specified, the maximum is equal to the minimum. If only maximum is specified, the minimum is 0. The decimal separator character of the output is internationalized (according the current locale setting), which means that it is not necessarily a dot. Unlike ${...}, #{...} ignores the number_format setting. This is actually a backward compatibility quirk, but it can be useful when you print numbers in situations like <a href="quertyDatabase?id=#{id}">, where you surely don't want grouping separators or something fancy like that. However, starting from FreeMarker 2.3.3 rather use the ?c built-in for this purpose, like <a href="quertyDatabase?id=${id?c}">. Examples. Assume that x is 2.582 and y is 4: <#-- If the language is US English the output is: --> #{x} <#-- 2.582 --> #{y} <#-- 4 --> #{x; M2} <#-- 2.58 --> #{y; M2} <#-- 4 --> #{x; m1} <#-- 2.6 --> #{y; m1} <#-- 4.0 --> #{x; m1M2} <#-- 2.58 --> #{y; m1M2} <#-- 4.0 -->
Appendixes FAQ FAQ JSP versus FreeMarker? JSP Note: JSP 1.x was really bad as an MVC template engine because it was not made for that, so I don't deal with that here. We compare FreeMarker with the JSP 2.0 + JSTL combo. FreeMarker Pros: FreeMarker is not tied to Servlets, networking or the Web; it is just a class library to generate text output by merging a template with Java objects (the data-model). You can execute templates anywhere and anytime; no HTTP request forwarding or similar tricks needed, no Servlet environment needed at all. Because of this you can easily integrate it into any system. No servlet specific scopes and other highly technical things in templates. It was made for MVC from the beginning, it focuses only on the presentation. You can load the templates from anywhere; from the class path, from a data-base, etc. Locale sensitive number and date formatting by default. Since we mostly output for a human audience all you need to do is just write ${x} rather than <fmt:formatNumber value="${x}" />. You can easily switch this behavior and output non-localized numbers by default. Easier to define ad-hoc macros and functions. No sweeping errors under the carpet. Missing variables will cause an error by default, and not silently default to arbitrary values. Also, null-s are not treated silently as 0/false/empty string. See more about this here... ``Object wrapping''. This lets you show the objects to templates in a customized, presentation oriented way (e.g. see here how a W3C DOM nodes can be seen by templates using this technology.) Macros and functions are just variables (compare it to how JSP custom tags work), so they can be easily passed around as parameter values, put into the data-model, ...etc, just like any other value. Easier to read, more terse syntax. For example: <#if x>...</#if> instead of <c:if test="${x}">...</c:if> Virtually unnoticeable delay when visiting a page for the first time (or after it was changed), because no expensive compilation happens. FreeMarker Cons: Not a ``standard''. There are fewer tools and IDE integrations, fewer developers knows it and there's much less industry support in general. (However, JSP tag libraries work without modification in FreeMarker templates, if they are not using .tag files.) Since macros and function are just variables, incorrect directive and parameter names and missing required parameters can be detected only on runtime. Its syntax doesn't follow the HTML/XML rules apart from some visual similarity, which is confusing for new users. (It's the price of the terseness...) Doesn't work with JSF. (It could work technically, but nobody has implemented that yet.) You may read this if you are considering replacing JSP with FreeMarker: Velocity versus FreeMarker? Velocity Velocity is a simpler, more lightweight tool. Thus, it does not address many tasks that FreeMarker does, and its template language is less powerful in general, but it is simpler; visit http://freemarker.org/fmVsVel.html for details. Currently (2005) Velocity has wider third party support and larger user community. Why is FreeMarker so picky about null-s and missing variables, and what to do with it? To recapitulate what's this entry is about: FreeMarker by default treats an attempt to access a non-existent variable or a null value (this two is the same for FreeMarker) as error, which aborts the template execution. First of all, you should understand the reason of being picky. Most scripting languages and template languages are rather forgiving with missing variables (and with null-s), and they usually treat them as empty string and/or 0 and/or logical false. This behavior has several problems: It potentially hides accidental mistakes, like a typo in a variable name, or when the template author refers to a variable that the programmer doesn't put into the data-model, or for which the programmer uses a different name. Human is prone to do such accidental mistakes, computers are not, so missing this opportunity that the template engine can show these errors is a bad business. Even if you very carefully check the output of the templates during development, it is easy to look over mistakes like <#if hasDetp>print dept here...</#if>, which would then silently never print the dept of the visitor, since you have mistyped the variable name (it should be hasDept). Also think about maintenance, when you later modify your application... most probably you will not re-check templates that carefully each time. Makes dangerous assumptions. The script language or template engine knows nothing about the application domain, so when it decides the value of something it don't know to be 0/false, it is a quite irresponsible and arbitrary thing. Just because it is not know what's your current bank account balance, can we just say it is $0 (and how easy it is to accidentally write Balance: ${balanace})? Just because it is not known if a patient has penicillin allergy, we can just say he/she doesn't have (and how easy it is to accidentally write <#if hasPenicilinAllergy>Warning...<#else>Allow...</#if>; there is a typo in this, if you didn't see)? Just consider the implications of such mistakes for a moment. They can be quite severe and troubling. Showing an error page is often better than showing incorrect information that formally looks good. Being not picky is mostly sweeping under the carpet in this case (not facing with the problems), which of course most people feels more convenient, but still... we believe that in most cases being strict will save your time and increase your software quality in the long run. On the other hand, we recognize that there are cases where you don't want FreeMarker to be that picky with good reason, and there is solution for them: It's often normal that your data-model contains null-s or have optional variables. In such cases use these operators. If you use them too often, try to rethink your data-model, because depending on them too much is not just results in awkward verbose templates, but increases the probability of hiding errors and printing arbitrary incorrect output (for the reasons described earlier). On a production server you may rather want to show an incomplete/damaged page than an error page. In this case you can use other error handler than the default. Error handlers can be made that rather skip the problematic part than abort the whole page rendering. Note, however, that although the error handlers don't give arbitrary default values to variables, for pages that show critical information it's maybe still better to show an error page. (Another feature you may interested in: the attempt/recover directives) The documentation writes about feature X, but it seems that FreeMarker doesn't know that, or it behaves in a different way as documented, or a bug that was supposedly fixed is still present. Are you sure that you are using the documentation written for the same version of FreeMarker that you actually use? Especially, note that our online documentation is for the latest usable FreeMarker release. You may use an older release. Are you sure that the Java class loader finds the same freemarker.jar that you expect to use? Maybe there is an older version of freemarker.jar around (such as in the Ant lib directory), which has higher priority. To check this, try to print the version number in a template with ${.version}. If it dies with ``Unknown built-in variable: version'' error message, then you use a release before 2.3-final or 2.2.8, but you can still try to get the version number in the Java code of your application with Configuration.getVersionNumber(). If this method is not present either, then you are using an early 2.3-preview, or a version before 2.2.6. If you think that the documentation or FreeMarker is wrong, please report it using the bug tracker, or the mailing list, or the forums on http://sourceforge.net/projects/freemarker/. Thank you! Why does FreeMarker print the numbers with strange formatting (as 1,000,000 or 1 000 000 instead of 1000000)? FreeMarker uses the locale-sensitive number formatting capability of the Java platform. The default number format for your locale may uses grouping or other unwanted formatting. To prevent this, you have to override the number format suggested by the Java platform with the number_format FreeMarker setting. For example: cfg.setNumberFormat("0.######"); // now it will print 1000000 // where cfg is a freemarker.template.Configuration object Note however than humans often find it hard to read big numbers without grouping separator. So in general it is recommended to keep them, and in cases where the numbers are for ''computer audience'' that is confused on the grouping separators, use the c built-in. For example: <a href="/shop/productdetails?id=${product.id?c}">Details...</a> Why does FreeMarker print bad decimal and/or grouping separator symbol (as 3.14 instead of 3,14)? Different countries use different decimal/grouping separator symbols. If you see incorrect symbols, then probably your locale is not set properly. Set the default locale of the JVM or override the default locale with the locale FreeMarker setting. For example: cfg.setLocale(java.util.Locale.ITALY); // where cfg is a freemarker.template.Configuration object However, sometimes you want to output a number not for human audience, but for ``computer audience'' (like you want to print a size in CSS), in which case you must use dot as decimal separator, regardless of the locale (language) of the page. For that use the c built-in, for example: font-size: ${fontSize?c}pt; Why does FreeMarker give an error when I try to print a boolean like ${aBoolean}, and how to fix it? Unlike numbers, booleans has no commonly accepted format, not even a common format within the same page. Like when you show on a HTML page if a product is washable, you will hardly want to show for the visitor "Washable: true", but rather "Washable: yes". So we force the template author (by ${washable} causing error) to find out with his human knowledge how the boolean value should be shown at the given place. The common way of formatting a boolean is like ${washable?string("yes", "no")}, ${caching?string("Enabled", "Disabled")}, ${heating?string("on", "off")}, etc. However, for generating source code ${washable?string("true", "false")} would be very often used, so ${washable?string} (i.e., omitting the parameter list) is equivalent with that. The < and > of FreeMarker tags confuses my editor or the XML parser. What to do? Starting from FreeMarker 2.3.4 you can use [ and ] instead of < and >. For more details read this... What are the legal variable names? variables names FreeMarker has no limitations regarding the characters used in variable names, nor regarding the length of the variable names, but for your convenience try to chose variable names that can be used with the simple variable reference expressions (see it here). If you have to choose a more extreme variable name, that's not a bid problem either: see here. How can I use variable (macro) names that contain space, dash or other special characters? If you have a variable with strange name, such as foo-bar, FreeMarker will misinterpret what do you want when you write thing as ${foo-bar}. In this concrete case, it will believe that you want subtract the value of bar from foo. This FAQ entry explains how to handle situations like this. First of all it should be clean that these are just syntactical problems. FreeMarker has no limitations regarding the characters used in variable names, nor regarding the length of the variable names, but sometimes you need to use syntactical tricks. If you want to read the variable: Use the square bracket syntax. An example of square bracket syntax is baaz["foo"], which is equivalent with baaz.foo. As the subvariable name with the square bracket syntax is a string literal (in fact, arbitrary expression), it let you write baaz["foo-bar"]. Now you may say that it can be used for hash subvariables only. Yes, but top-level variables are accessible through special hash variable .vars. For example, foo is equivalent with .vars["foo"]. So you can also write .vars["foo-bar"]. Naturally, this trick works with macro invocations too: <@.vars["foo-bar"]/> If you want to create or modify the variable: All directives that let you create or modify a variable (such as assign, local, global, macro, function, etc.) allows the quotation of the destination variable name. For example, <#assign foo = 1> is the same as <#assign "foo" = 1>. So you can write things like <#assign "foo-bar" = 1> and <#macro "foo-bar">. Why do I get "java.lang.IllegalArgumentException: argument type mismatch" when I try to use X JSP custom tag? On JSP pages you quote all parameter (attribute) values, it does not mater if the type of the parameter is string or boolean or number. But since custom tags are accessible in FTL templates as plain user-defined FTL directives, you have to use the FTL syntax rules inside the custom tags, not the JSP rules. Thus, according to FTL rules, you must not quote boolean and numerical parameter values, or they are interpreted as string values, and this will cause a type mismatch error when FreeMarker tries to pass the value to the custom tag that expects non-string value. For example, the flush parameter to Struts Tiles insert tag is boolean. In JSP the correct syntax was: <tiles:insert page="/layout.jsp" flush="true"/> ... but in FTL you should write: <@tiles.insert page="/layout.ftl" flush=true/> ... Also, for similar reasons, this is wrong: <tiles:insert page="/layout.jsp" flush="${needFlushing}"/> ... and you should write: <tiles:insert page="/layout.jsp" flush=needFlushing/> ... (Not flush=${needFlushing}!) How to include other resources in a way as jsp:include does it? Not with <#include ...>, as that just includes another FreeMarker template without involving the Servlet container. Since the inclusion method you look for is Servlet-related, and pure FreeMarker is unaware of Servlets or even HTTP, it's the Web Application Framework that decides if you can do this and if so how. For example, in Struts 2 you can do this like this: <@s.include value="/WEB-INF/just-an-example.jspf" /> If the FreeMarker support of the Web Application Framework is based on freemarker.ext.servlet.FreemarkerServlet, then you can also do this (since FreeMarker 2.3.15): <@include_page path="/WEB-INF/just-an-example.jspf" /> but if the Web Application Framework provides its own solution, then you may prefer that, after all it may does something special. For more information about include_page read this... How can I get the parameters to my plain-Java-method/TemplateMethodModelEx/TemplateTransformModel/TemplateDirectiveModel implementation as plain java.lang.*/java.util.* objects? Unfortunately, there is no simple general-purpose solution for this problem. The problem is that FreeMarker object wrapping is very flexible, which is good when you access variables from templates, but makes unwrapping on the Java side a tricky question. For example, it is possible to wrap a non-java.util.Map object as TemplateHashModel (FTL hash variable). But then, it can't be unwrapped to java.util.Map, since there is no wrapped java.util.Map around at all. So what to do then? Basically there are two cases: Directives and methods that are written for presentation purposes (like kind of ``tools'' for helping FreeMarker templates) should declare their arguments as TemplateModel-s and the more specific sub interfaces of that. After all, the object wrapping is about apparently transforming the data-model to something that serves the purpose of the presentation layer, and these methods are part of the presentation layer. Methods that are not for presentation related tasks (but for business logic and like) should be implemented as plain Java methods, and should not use any FreeMarker specific classes at all, since according the MVC paradigm they must be independent of the presentation technology (FreeMarker). If such a method is called from a template, then it is the responsibility of the object wrapper to ensure the conversion of the arguments to the proper type. If you use the DefaultObjectWrapper or the BeansWrapper then this will happen automatically (but be sure you are using at least FreeMarker 2.3.3). Furthermore if you use BeansWrapper, then the method will surely get exactly the same instance that was earlier wrapped (as far as it was wrapped by the BeansWrapper). Why I can't use non-string key in the myMap[myKey] expression? And what to do now? hash key type The ``hash'' type of the FreeMarker Template Language (FTL) is not the same as Java's Map. FTL's hash is an associative array too, but it uses string keys exclusively. This is because it was introduced for subvariables (as password in user.password, which is the same as user["password"]), and variable names are strings. So FTL's hashes are not general purpose associate arrays that could be used for looking up values with keys of arbitrary type. FTL is presentation oriented language, and it has no feature dedicated for that purpose. It has, however, methods. Methods are part of the data-model, and they can do all kind of fancy data-model related calculations, so of course you can add some methods to the data-model for Map lookup. The bad news is that the building of the data-model, as it's an application specific issue, is the task of the programmers who use FreeMarker, so it's their task to ensure that such methods are present there to serve the template authors. (However, when template authors need to call methods that are not about presentation, then consider if the data-model is simple enough. Maybe you should push some calculations back to the data-model building phase. Ideally the data-model contains what should be displayed, and not something that serves as the base of further calculations.) If you read the programmer's guide, then you know that technically, the data-model is a tree of freemarker.template.TemplateModel objects. The building of the data-model usually (but not necessary) happens by automatically wrapping (enclosing) plain Java objects into TemplateModel objects. The object that does this wrapping is the object wrapper, and it's specified when you configure FreeMarker. FreeMarker comes with a few object wrapper implementations out-of-the-box, and probably the most widely used of them is freemarker.ext.beans.BeansWrapper. If you use an instance of this as the object wrapper, then java.util.Map-s you put into the data-model will also act as a method, so you can write myMap(myKey) in the template, that will internally call Map.get(myKey). There will be no restriction regarding the type of myKey, as Map.get(Object key) has no such restriction. If the value of myKey was wrapped with BeansWrapper or other object wrapper whose wrapped objects support unwrapping, or it is given as literal in the template, then the value will be automatically unwrapped to plain Java object before the actual invocation of the Map.get(Object key) method, so it will not be invoked with TemplateModel-s. But there still will be a problem. Java's Map is particular about the exact class of the key, so for numerical keys calculated inside the templates you will have to cast them to the proper Java type, otherwise the item will not be found. For example if you use Integer keys in a Map, then you have to write ${myMap.get(123?int)}. This is an ugly effect caused by that FTL's deliberately simplified type system just has a single numerical type, while Java distinguishes a lot of numerical types. (Ideally, in the above case, the programmers ensure that the get method automatically converts the key to Integer, so it's not the problem of the template author. This can be done with wrapper customization, but the wrapper has to know that the particular Map object uses Integer keys, which assumes application specific knowledge.) Note that the casting is not needed when the key value comes directly from the data-model (i.e. you didn't modified its value with arithmetical caluclations in the template), including the case when it's the return value of a method, and it was of the proper class before wrapping, because then the result of the unwrapping will be of the original type. When I list the contents of a map (a hash) with ?keys/?values, I get the java.util.Map methods mixed with the real map entries. Of course, I only want to get the map entries. Certainly you are using BeansWrapper as your object wrapper, or a custom subclass of it, and the simpleMapWrapper property of that is left to false. Unfortunatelly, it's the default (for backward compatibility), so you have to explicitly set it to true where you create the object wrapper. How can I modify sequences (lists) and hashes (maps) in FreeMarker templates? modify hashes modify sequences sequence modify hash modify First of all, you may don't want to modify the sequence/hash, just concatenate (add) two or more of them, which results in a new sequence/hash, rather than modifying an existing one. In this case use the sequence concatenation and hash concatenation operators. Also, you may use the subsequence operator instead of removing sequence items. However, be aware of the performance implications: these operations are fast, but the hashes/sequences that are the result of many subseqent applications of these operations (i.e. when you use the result of the operation as the input of yet another operation, and so on) will be slow to read. Now if you still want to modify sequences/hashes, then read on... The FreeMarkes Template Language doesn't support the modification of sequences/hashes. It's for displaying already calculated things, not for calculating data. Keep templates simple. But don't give it up, you will see some advices and tricks bellow. The best is if you can divide the work between the data-model builder program and the template so that the template doesn't need to modify sequences/hashes. Maybe if you rethink your data-model, you will realize this is possible. But, seldom there are cases where you need to modify sequences/hashes for some complex but purely presentation related algorithms. It seldom happens, so think twice whether that calculation (or parts of it) rather belongs to the data-model domain than to the presentation domain. Let's assume you are sure it belongs to the presentation domain. For example, you want to display a keyword index on some very smart way, whose algorithm need you to create and write some sequence variables. Then you should do something like this (ugly situations has ugly solutions...): <#assign caculatedResults = 'com.example.foo.SmartKeywordIndexHelper'?new().calculate(keywords)> <#-- some simple algorithms comes here, like: --> <ul> <#list caculatedResults as kw> <li><a href="${kw.link}">${kw.word}</a> </#list> </ul> That is, you move out the complex part of the presentation task from the template into Java code. Note that it doesn't affect the data-model, so the presentation is still kept separated from other the other application logic. Of course the drawback is that for this the template author will need the help of a Java programmer, but for complex algorithms that's probably needed anyway. Now, if you still say you need to modify sequences/hashes directly with the FreeMarker template, here are two solutions, but please read the warning after them: You can write a TemplateMethodModelEx and TemplateDirectiveModel implementation that can modify certain types of sequences/hashes. Just certain types, because TemplateSequenceModel and TemplateHashModel doesn't have methods for modification, so you will need the sequence or hash to implement some additional methods. An example of this solution can be seen in FMPP. It allows you to do things like this (pp stores the services provided by FMPP for templates): <#assign a = pp.newWritableSequence()> <@pp.add seq=a value="red" /> The pp.add directive works only with sequences that were created with pp.newWritableSequence(). So for example the template author can't modify a sequence that comes from the data-model with this. A sequence can have some methods/directives if you use a customized wrapper (so you can <@myList.append foo />). (Also, if you use BeansWrapper and configure it so it exposes the public methods, you can use the Java API for variables that are for java.util.Map-s and java.util.List-s. Just like with Apache Velocity.) But beware, these solutions have a problem: The sequence concatenation, sequence slice operator (like seq[5..10]) and ?reverse do not copy the original sequence, just wraps it (for efficiency), so the resulting sequence will change if the original sequence is changed later (an abnormal aliasing effect). The same problem exists with the result of hash concatenation; it just wraps the two hashes, so the resulting hash will magically change if you modify the hashes you have added earlier. As a work-around, after you did the above problematic operations, either be sure you will not modify the objects that were used as input, or create a copy of the result with a method provided by the solution described in above two points (e.g. in FMPP you could do <#assign b = pp.newWritableSequence(a[5..10])> and <#assign c = pp.newWritableHash(hashA + hashB)>). Of course this is easy to miss... so again, rather try to build the data-model so you will not need to modify collections, or use a presentation task helper class as was shown earlier. What about null and the FreeMarker template language? null The FreeMarker template language doesn't know the Java language null at all. It doesn't have null keyword, and it can't test if something is null or not. When it technically faces with a null, it treats it exactly as a missing variable. For example, both if x is null in the data-model and if it's not present at all, ${x!'missing'} will print ``missing'', you can't tell the difference. Also, if for example you want to test if a Java method has returned null, just write something like <#if foo.bar()??>. You may interested in the rationale behind this. From the viewpoint of the presentation layer a null and non-existent thing is almost always the same. The difference between this two is usually just a technical detail, which is rather the result of implementation details than of the application logic. That you can't compare something to null (unlike in Java); it doesn't make sense to compare something with null in a template, since the template language doesn't do identity comparison (like the Java == operator when you compare two objects) but the more common sense value comparison (like Java's Object.equals(Object); that doesn't work with null either). And how could FreeMarker tell if something concrete equals with something that is missing and thus unknown? Or if two missing (unknown) things are equal? Of course these questions can't be answered. There is at least one problem with this null-unaware approach. When you call a Java method from a template, you may want to pass a null value as argument (since the method was designed to be used in Java language, where the concept of null is known). In this case you can exploit a bug of FreeMarker (that we will not fix until we provide a correct solution for passing null values to a method): if you specify a missing variable as the argument, then it will not cause an error, but a null will be passed to the method instead. Like foo.bar(nullArg) will call the bar method with null as argument, assuming that there is no varaible exists with ``nullArg'' name. How can I use the output of a directive (macro) in expressions (as a parameter to another directive)? Capture the output into a variable with the assign or local directive. For example: <#assign capturedOutput><@outputSomething /></#assign> <@otherDirective someParam=capturedOutput /> Why do I have ``?''-s in the output instead of character X? This is because the character that you want to print can't be represented with the charset (encoding) used for the output stream, so the Java platform (not FreeMarker) substitutes the problematic character with question mark. In general you should use the same charset for the output as for the template (use the getEncoding() method of the template object), or which is even safer, you should always use UTF-8 charset for the output. The charset used for the output stream is not decided by FreeMarker, but by you, when you create the Writer that you pass to the process method of the template. Example: Here I use UTF-8 charset in a servlet: ... resp.setContentType("text/html; charset=utf-8"); Writer out = resp.getWriter(); ... t.process(root, out); ... Note that the question marks (or other substitution characters) may be produced outside FreeMarker, in which case the above obviously will not help. For example a bad/missconfigured database connection or JDBC driver may bring the text already with substitution characters in it. HTML forms are another potential source of encoding problems. It's a good idea to print the numerical code of the characters of the string on various places, to see where the problem occurs first. You can read more about charsets and FreeMarker here... How to retrieve values calculated in templates after template execution done? First of all, be sure your application is designed well: templates should display data, and almost never calculate data. If you are still sure you want to do it, read on... When you use <#assign x = "foo">, then you do not actually modify the data-model (since that is read-only, see: ), but create the x variable in the runtime environment of the processing (see ). The problem is that this runtime environment will be discarded when Template.process returns, as it was created for a single Template.process call: // internally an Environment will be created, and then discarded myTemplate.process(root, out); To prevent this, you can do the below, which is equivalent with the above, except that you have chance to return the variables created in the template: Environment env = myTemplate.createProcessingEnvironment(root, out); env.process(); // process the template TemplateModel x = env.getVariable("x"); // get variable x security user-provided templates Can I allow users to upload templates and what are the security implications? In general you shouldn't allow that, unless those users are system administrators or other trusted personnel. Consider templates as part of the source code just like *.java files are. If you still want to allow users to upload templates, here are what to consider: Denial-of-Service (DoS) attacks: It's trivial to create templates that run practically forever (with a loop), or exhaust memory (by concatenating to a string in a loop). FreeMarker can't enforce CPU or memory usage limits, so this is something that has no solution on the FreeMarker-level. Data-model and wrapping (Configuration.setObjectWrapper): By default the data-model gives access to the full public API of the Java objects that you have put into the it (with some exceptions). To avoid that, you have to construct the data-model so that it only exposes the things that are necessary for the template. For that, use SimpleObjectWrapper and create the data-model purely from Map-s, List-s, Array-s, String-s, Number-s, Boolean-s and Date-s. Or, you can implement your own extremely restrictive ObjectWrapper, which for example could expose your POJO-s safely. Template-loader (Configuration.setTemplateLoader): Templates may load other templates by name (by path), like <#include "../secret.txt">. To avoid loading sensitive data, you have to use a TemplateLoader that double-checks that the file to load is something that should be exposed. FreeMarker tries to prevent the loading of files outside the template root directory regardless of template loader, but depending on the underlying storage mechanism, exploits may exist that FreeMarker can't consider (like, just as an example, ~ jumps to the user directory). Note that freemarker.cache.FileTemplateLoader checks the canonical paths, so that's maybe a good candidate for this task, yet, adding a file extension check (file must be *.ftl) is maybe a good idea. The new built-in (Configuration.setNewBuiltinClassResolver, Environment.setNewBuiltinClassResolver): It's used in templates like "com.example.SomeClass"?new(), and is important for FTL libraries that are partially implemented in Java, but shouldn't be needed in normal templates. While new will not instantiate classes that are not TemplateModel-s, FreeMarker contains a TemplateModel class that can be used to create arbitrary Java objects. Other "dangerous" TemplateModel-s can exist in you class-path. Plus, even if a class doesn't implement TemplateModel, its static initialization will be run. To avoid these, you should use a TemplateClassResolver that restricts the accessible classes (possibly based on which template asks for them). How to implement a function or macro in Java Language instead of in the template language? It's not possible (yet), but something very similar is possible if you write a class that implements freemarker.template.TemplateMethodModelEx or freemarker.template.TemplateDirectiveModel respectively, and then where you were write <#function my ...>...</#function> or <#macro my ...>...</#macro> you write <#assign my = "your.package.YourClass "?new()> instead. Note that using the assign directive for this works because functions (and methods) and macros are just plain variables in FreeMarker. (For the same reason you could also put TemplateMethodModelEx or TemplateDirectiveModel instances into the data-model before calling the template, or into the shared variable map (see: freemarker.template.Configuration.setSharedVariable(String, TemplateModel)) when you initialize the application.) Why is FreeMarker logging suppressed for my application? It's because FreeMarker does not find any logging system. To fix this, you must make available one of the following logging systems for your application: SLF4J (recommended), Apache Commons Logging, Log4J (org.apache.log4j), Avalon (org.apache.log), or use J2SE 1.4 or later (that contains java.util.logging). That is, the class-loader used with your application must find one of the mentioned classes. Until 2.4, if you want to use SLF4J or Commons Logging you need to do some extra steps; see here... In my Servlet based application, how do I show a nice error page instead of a stack trace when error occurs during template processing? First of all, use RETHROW_HANDLER instead of the default DEBUG_HANDLER (for more information about template exception handlers read this...). Now FreeMarker will not print anything to the output when an error occurs, so the control is in your hands. After you have caught the exception of Template.process(...) basically you can follow two strategies: Call httpResp.isCommitted(), and if that returns false, then you call httpResp.reset() and print a ``nice error page'' for the visitor. If the return value was true, then try to finish the page be printing something that makes clear for the visitor that the page generation was abruptly interrupted because of an error on the Web server. You may have to print a lot of redundant HTML end-tags and set colors and font size to ensure that the error message will be actually readable in the browser window (check the source code of the HTML_DEBUG_HANDLER in src\freemarker\template\TemplateException.java to see an example). Use full page buffering. This means that the Writer doesn't send the output to the client progressively, but buffers the whole page in the memory. Since you provide the Writer instance for the Template.process(...) method, this is your responsibility, FreeMarker has nothing to do with it. For example, you may use a StringWriter, and if Template.process(...) returns by throwing an exception, then ignore the content accumulated by the StringWriter, and send an error page instead, otherwise you print the content of StringWriter to the output. With this method you surely don't have to deal with partially sent pages, but it can have negative performance implications depending on the characteristic of the pages (for example, the user will experience more response delay for a long page that is generated slowly, also the server will consume more RAM). Note that using a StringWriter is surely not the most efficient solution, as it often reallocates its buffer as the accumulated content grows. I'm using a visual HTML editor that mangles template tags. Will you change the template language syntax to accommodate my editor? We won't change the standard version, because a lot of templates depend on it. Our view is that the editors that break template code are themselves broken. A good editor should ignore, not mangle, what it doesn't understand. You maybe interested in that starting from FreeMarker 2.3.4 you can use [ and ] instead of < and >. For more details read this... How fast is FreeMarker? Is it true that 2.x is slower than 1.x (FreeMarker classic)? First of all, don't forget that FreeMarker is only the view rendering component in an MVC system. Furthermore MVC templates tend to be simple: many static text with a few interpolations and loops and conditional block. So it is not like PHP or Model 1 JSP; your application performance is not affected that much by the execution time of templates. FreeMarker is certainly fast enough that it will only very rarely be a bottleneck in your application. Rather, other factors such as the speed of the data-base operations or network bandwidth will likely dominate. The impact of FreeMarker performance could be noticeable only for really busy sites (say, over 30 hits per second per server), where almost all database data is cached. If you are finding FreeMarker slow, do make sure that the cache of parsed templates works well (Configuration.getTemplate be default uses caching). Parsing a template file is a relatively costly step; in most long-running server-side applications, you will want to parse a template once and have it be used many times. (Note that FreeMarker 2.1.4 and earlier versions have bugs that sometimes can ruin caching.) FreeMarker 2.1 is slower than 1.7.1. This surely depends on your templates, but it could be slower by a factor of 2 or 3. But again, it does not means that response time will be 2 or 3 times slower; most FreeMarker user simply should not be able to perceive the change in the final response time. How can my Java classes ask a template for information about its structure (e.g. a list of all the variables)? In FreeMarker 2.2, Template has an undocumented method for examining the parsed template: getRootTreeNode. But listing all accessed variables is not possible, because variable names can be dynamically generated from data. However, there's a more important reason why FreeMarker doesn't support this. The design of FreeMarker is based on the idea of a separation between business objects and presentation objects. This separation takes two forms: The templates know what data to expect, but they don't know how it's generated. The business objects know what data to produce, but they don't know how it's going to be displayed. Therefore, they don't know anything about templates. Since the business objects don't rely on the templates, if you need to use them with some other presentation system, you won't have to rewrite your application. Will you ever provide backward compatibility? FreeMarker 2.0 was a complete rewrite of FreeMarker 1.x, by a new author. The 1.x series continues as separated project: FreeMarker Classic. Since 2.x follows different philosophy than 1.x, 2.0x releases were immature despite the high major version number. This caused further radical changes between 2.01 and 2.1. As of 2.1 things were much more matured, and 2.2 is almost backward compatible with 2.1. We hope that this tendency continues. Currently, the rule is that releases with different second version number (as 2.1.x and 2.2.x) are not (fully) compatible. Releases where only the third version number differs (as 2.2.1 and 2.2.6) are compatible. We always provide backward compatible bugfix releases for the released versions. So basically, you don't have to switch to a new, non-backward compatible release in an already written product. It's a something for something situation... FreeMarker recovers faster from design mistakes than many other projects, but the price of this is that major releases are not backward compatible. This is admittedly not optimal, it would be better if there are fewer design mistakes... but, well, it is the reality. If we distribute FreeMarker with our product, do we have to release the source code for our product? No. As of 2.0, FreeMarker is released under a BSD-style license. This means that source or binary distributions may be made freely, and can be included in other products, whether commercial or open source. The only restrictions apply to the copyright of FreeMarker itself, and the use of FreeMarker or its contributors as endorsements of your own product. See the LICENSE for further details. If you use FreeMarker, we hope you'll send us a link to some information about your product, but that's optional as well. Installing FreeMarker install No real installation needed. Simply copy lib/freemarker.jar to a location where your Java application's class-loader will find it. For example, if you use FreeMarker in a web application, you probably want to put freemarker.jar into the WEB-INF/lib directory of your web application. No real installation needed. Simply copy lib/freemarker.jar to a location where your Java application's ClassLoader will find it. For example, if you use FreeMarker in a web application, you probably want to put freemarker.jar into the WEB-INF/lib directory of your web application. (If you want to use FreeMarker with JSP Model-2 style (which also means that you can use custom JSP taglibs in the templates), some extra steps needed. For more information please see the chapter about servlets.) However, some third party libraries have also be available for the class-loader, if you want to enable certain optional FreeMarker features: At least J2SE 1.4 is required for regular expression built-ins. At least J2SE 1.4 or a JAXP + DOM implementation + SAX implementation is needed for the XML wrapping. Jaxen (recommended, download here) or Apache Xalan is needed for XML XPath support. Please use at least Jaxen 1.1-beta-8, not older versions! Apache Xalan classes are included in Sun J2SE 1.4, 1.5 and 1.6 (and maybe later too), so no separate Xalan jar is needed with those versions. Obviously, javax.servlet classes are needed for FreemarkerServlet. Servlet version 2.2 or later is needed. For the custom JSP taglib support, you will need JSP 1.2 API classes. No JSP implementation needed, just the API. For more information please see the chapter about servlets. Obviously, Jython classes are needed for the Jython wrapper. JDOM is needed for the deprecated freemarker.ext.jdom package. Building FreeMarker build If you want to modify the source code and rebuild freemarker.jar, you need Ant 1.6.1 (or newer) and JDK 5 (or newer). If these are satisfied, just run Ant from the root directory of the distribution, and it will create the new freemarker.jar. Note that for the very first build you must be on-line, because the build task will download a lot of required dependencies (about 20 MB) into the lib subdirectory of distribution root directory. Maybe you should check the new jar file against our test suite. This is done by running Ant with test target (go to the root directory of the distribution, and issue "ant test"). If the test fails, read the resulting .txt file in the build/testcase directory for more details. Note that building a full distribution, which includes the FreeMarker Manual and the off-line Web site, is not possible purely from the source code that is included with the distribution. You will have to check out the "docgen" and "site" sub-projects from the SVN repository of FreeMarker for that. Versions
2.3.19 Date of release: 2012-02-29 Don't miss the security related changes, they may affect your application!
Changes on the FTL side Attention: The output of ISO 8601 date/time formatting built-ins, introduced in 2.3.17, was slightly changed. From now on, the time zone offset, when it's displayed and it isn't Z, always includes the minutes. For example, 15:30:15+02 becomes to 15:30:15+02:00 in the template output. Both formats are valid according to ISO 8601 (so anything that expects ISO 8601 date/times should continue working), but only the last format complies with the XML Schema date/time formats, hence this change. New built-in for escaping inside JSON string literals: json_string. Bugfix: Wrong # tags were printed as static text instead of causing parsing error if there was no correct # tag earlier in the same template. Since fixing this would not be 100% backward compatible, the old behavior has remained, unless you set the incompatible_enhancements setting (Configuration.setIncompatibleEnhancements(String)) to "2.3.19" or higher.
Changes on the Java side Attention: This release contains two important security workarounds that unavoidably make it obvious how some applications can be exploited. FreeMarker can't solve these issues on all configurations, so please read the details instead of just updating FreeMarker! Also, these changes are not 100% backward compatible in theory, however it's not probable that they will break anything. The two changes are: The character with character code 0 (\u0000) is not allowed in template paths anymore. When a path contains it, FreeMarker behaves as if the template was not found. This is to fix the security problem where a template path like "secret.txt\u0000.ftl" is used to bypass extension filtering in an application. FreeMarker itself doesn't care about the extension, but some applications decide based on the extension if they will delegate a path to FreeMarker. When they do with such a path, the C/C++ implementation behind the storage mechanism may sees the path as "secret.txt" as the 0 terminates the string in C/C++, and thus load a non-FTL file as a template, returning the file contents to the attacker. Note that some HTTP servers, notably Tomcat and Apache will block URL-s containing 0, but some others, like Jetty, doesn't. ClassTemplateLoader, when it's created with base path "/" (like with new ClassTemplateLoader(someClass, "/")), will not allow template paths that contain colon earlier than any /, and will act like if the template was not found in such case. This is to fix the security problem where a template path like "file:/etc/secret" or "http://example.com/malware.ftl" is interpreted as a full URL by a java.net.URLClassLoader in the class-loader hierarchy. This is a quirk (or bug) of java.net.URLClassLoader. Beware, some frameworks use their own TemplateLoader implementations, and if those are vulnerable, they will remain so after updating FreeMarker too! Note that this exploit only works if the class-loader hierarchy contains an URLClassLoader and the class-loader is used to load templates without adding any prefix before the template path (other than "/"). These security issues mostly affect applications where the user (the visitor) can supply arbitrary template paths. This is not the case with properly built MVC applications, as there only the Controller can be addressed directly, and it's the Controller who specifies the template paths. But MVC applications based on JSP Model-2 often expose the MVC Views as URL-s ending with .ftl, thus allowing the user to give arbitrary paths to FreeMarker. Such applications should be secured with a security-constratint in web.xml as shown in the related Manual section. This should be done regardless of the current security fixes. Configuration has new methods: removeTemplateFromCache(...). This will remove the given template for the given locale from the cache, so it will be re-loaded regardless of the template update delay when it's next time requested. BeansWrapper ignores setter methods from now when introspecting classes. They weren't used anyway, so they unnecessarily caused "java.beans.IntrospectionException: type mismatch between read and write methods" errors. TemplateClassResolver.SAFER_RESOLVER now disallows creating freemarker.template.utility.JythonRuntime and freemarker.template.utility.Execute. This change affects the behavior of the new built-in if FreeMarker was configured to use SAFER_RESOLVER, which is not the default until 2.4 and is hence improbable. Bug fixed: Calling varargs methods now indeed works. (Earlier it only worked for overloaded methods.) Bug fixed [1837697] [2831150] [3039096] [3165425]: Jython support now works with Jython 2.2 and 2.5. Bug fixed [3325103]: TemplateException-s and ParseException-s are now serializable.
2.3.18 Date of release: 2011-05-21
Changes on the Java side Bugfix [3304568]: 2.3.17 didn't find TLD-s in WEB-INF\lib\*.jar unless they were explicitly pointed in the web.xml with a taglib element. This bug was introduced in 2.3.17.
Other changes Added LICENSE.txt and NOTICE.txt to freemarker.jar under META-INF.
2.3.17 Date of release: 2011-05-17 It's possibly urgent to update to this version because of a security fix!
Changes on the FTL side ?seq_index_of and ?seq_last_index_of now works on collections (freemarker.template.TemplateCollectionModel-s) too, not only on sequences (freemarker.template.TemplateSequenceModel-s). ?long now works for date, date-time or time values, and returns the milliseconds since the epoch (as java.util.Date.getTime()). To convert numbers (usually Java long-s) to date or date-time and time values, ?number_to_date, ?number_to_time, ?number_to_datetime was added. See more here... (Unfortunately, ?date and like can't be extended to support this due to backward compatibility issues.) New built-ins to format numbers with ISO 8601 "extended" format regardless of the current date/time formatting settings, and even regardless of the current time zone setting. For example ${myTimeStamp?iso_utc} will print something like 2010-05-16T23:05:45Z. See more here... New special variable, now. This returns the current date-time. Usage examples: "Page generated: ${.now}", "Today is ${.now?date}", "The current time is ${.now?time}". ?sort and ?sort_by now supports sorting boolean values. When using unsupported or unknown string built-in flags, FreeMarker will now log warnings (maximum 25 times per class-loader, to prevent flooding the log). It's certain that starting from FreeMarker 2.4 these will count as errors. Bug fixed [3047201]: Using regular expressions (like with ?match) could cause lockup in multi-threaded environment, also memory leakage when using dynamically generated regular expressions. Bug fixed: ?seq_contains, ?seq_index_of and ?seq_last_index_of has failed with non-java.util.List java.util.Collection-s that are wrapped with pure BeansWrapper (not the DefaultObjectWrapper) as TemplateSequenceModel. (See also: getSupportsIndexedAccess() below)
Changes on the Java side Security fix: Using carefully crafted template names (template paths) that contain code point 0 ('\u0000'), it was possible to load files from outside the template root directory like if they were FreeMarker templates. The root of the problem is that the underlying native C/C++ part (which belongs to the Java platform or to the OS) interprets the 0 as the end of the string, while Java (and hence FreeMarker and the Servlet container) doesn't. Thus a path that looked safe for FreeMarker become unsafe on the lower level. The problem is present with all ways of loading templates by name (Configuration.getTemplate(...), <#include ...>, <#import ...>). You are not effected if you don't allow users to upload templates and also at least one of these stands: In your system users can't provide arbitrary strings as template names (template paths). For example, if users are only allowed to visit the URL-s that belong to the MVC Controller (like they can't visit *.ftl) then they can't suggest arbitrary template names. The template names are part of the path in the Web page URL, and your webserver or Servlet container disallows URL-s that contain %00, or terminate the URL at it before passing it to the servlets. You are using FileTemplateLoader and linking is not allowed in it (by default it isn't allowed). FreeMarker now can log its messages directly using SLF4J or Apache Commons Logging. However, it will not use these logger libraries automatically, until 2.4; see more here... But it's recommended to switch to SLF4J now. New setting: "auto_flush", Configurable.setAutoFlush(boolean). Sets whether the output Writer is automatically flushed at the end of Template.process(Object, Writer) (and its overloads). The default is true, which corresponds to the earlier behavior. Using false is needed for example when a Web page is composed from several boxes (like portlets, GUI panels, etc.) that aren't inserted with #include (or with similar directives) into a master FreeMarker template, rather they are all processed with a separate Template.process(...) call. In a such scenario the automatic flushes would commit the HTTP response after each box, hence interfering with full-page buffering, and also possibly decreasing performance with too frequent and too early response buffer flushes. Added new setting: Configuration.setNewBuiltinClassResolver(TemplateClassResolver), or new_builtin_class_resolver property. This allows you to specify how the new built-in (like in "com.example.SomeClass"?new()) resolves classes and which classes are accessible at all. If you are allowing not-so-much-trusted users to upload templates, you should be definitely interested; see the Java API docs of freemarker.core.Configurable.setSetting and freemareker.template.Configuration.setNewBuiltinClassResolver. Otherwise it's still recommended to set this to TemplateClassResolver.SAFER_RESOLVER (or safer if you are using properties), although that's not 100% backward compatible (see Java API docs) . Added freemarker.cache.NullCacheStorage: Setting this as the cache storage in Configuration disables caching. Added getSupportsIndexedAccess() to freemarker.ext.beans.CollectionModel, so one can check if TemplateSequenceModel.get(int) will work with a particular CollectionModel instance or not. Bug fixed [2992265]: JSP FreeMarkerPageContext.include behaved incorrectly. Bug fixed: When using FreeMarker's JSP support with JSP tags that use javax.servlet.jsp.PageContext.pushBody (like some Stripes tags), "ArrayIndexOutOfBoundsException: -1" occurred inside freemarker.ext.jsp.FreeMarkerPageContext.popWriter. Bug fixed [3033015]: AllHttpScopesHashModel used WrappingTemplateModel.getDefaultObjectWrapper() for wrapping variables in the page scope, while used the user-specified ObjectWrapper for all other scopes (request, session, etc.). Now it uses the user-specified wrapper in the page scope as well. Bug fixed [3128073]: HashAdapther.containsKey(...) returned true for a key that doesn't exist when unwrapping the key has failed. As a side effect of the fix, BeansWrapper.CAN_NOT_UNWRAP is now private; earlier it was public by mistake. Big fixed [3151085]: freemarker.jsp.TaglibFactory didn't locate tld files properly. This fix gives better compliance with JSP specification for resolving and loading tld files. Bug fixed: Unwrapping null with a BeansWrapper that had a custom null-model didn't result in null. Now both unwrapping null and the custom null-model gives null. Log messages doesn't contain line-breaks (CR or LF) anymore and quote paths and other arbitrary text with Java string literal syntax that also escapes < characters as \u003C. These address security concerns related to poor quality log appenders and buggy log readers. This change is mostly noticeable on template processing error entries, which will now quote the exception message. Note that how stack traces (the Throwable objects) are logged is still up to the logging framework you are using.
Other changes The DTD-s and XSD-s that are included in freemarker.jar under freemarker/ext/jsp are now under Apache Software License, Version 2. This is also clarified in the LICENSE.txt. Earlier these files had no clear license terms.
2.3.16 Date of release: 2009-12-07
Changes on the Java side Fixed a bug that caused incorrect unwrapping of sequences to Java arrays (See bug report) Fixed a bug that caused rounding of float and double values (See bug report) Created a new freemarker.runtime.attempt category and exceptions caught in <#attempt> blocks are logged into it at a DEBUG severity. Fixing the (ages old) problem of RhinoWrapper not working with all versions of Rhino because of binary incompatible change of Rhino's Undefined.instance. Fixed bug where TextUtil.XMLEncNQG didn't escape ]]> as ]]&gt;. Fixed bug where the root directory couldn't be used as the template base directory, as FileTemplateLoader believed that the template is outside the base directory. Macro names can no longer be changed through the API. FreemarkerServlet now cooperates with Session Fixation Attack Protection in Spring Security, see forum discussion for details. Substantially improved performance of the <#return> directive.
Changes on the FTL side Fixed bug where anXMLNode.@@markup and @@nested_markup didn't escape ]]> as ]]&gt;.
2.3.15 Date of release: 2008-12-16
Changes on the FTL side Bug fixed: Hash concatenation (like hash1 + hash2) shuffled the order of keys/values even if both hashes were ordered. In web pages that are based on the FreemarkerServlet, you can now use <@include_page path="..."/> to use servlet includes. See more here...
Changes on the Java side The BeansWrapper can automatically detect that classes were reloaded by JavaRebel. Fixed a bug that caused null to be returned from Environment.getCurrentEnvironment() while processing autoincludes and autoimports. (See bug report) Fixed a bug that caused getObject(Object) method on POJOs to not be recognized as a general get method. Substantially improved performance of the <#break> directive. DeepUnwrap now unwraps custom null model of the current object wrapper into a Java null.
2.3.14 Date of release: 2008-09-01
Changes on the FTL side New built-in: xhtml. See more here... New special variable: template_name. See more here... Now you can use the values of parameters as the defaults of other parameters, for example <#macro section title label=title>. In earlier versions it worked unreliably. There are no restriction regarding the order of parameters, like <#macro section label=title title> works too. Added a new number format specifier, computer. This uses the same formatting as exp?c.
Changes on the Java side The constructor to freemarker.ext.servlet.AllHttpScopesHashModel is now public, allowing it to be reused in 3rd party web frameworks. Bugfix: freemarker.ext.beans.SimpleMapModel (unlike either freemarker.ext.beans.MapModel or freemarker.template.SimpleHash) didn't allow lookup by java.lang.Character key when passed a single-character string as a key. Bugfix: permissive unwrapping in freemarker.template.utility.DeepUnwrap class was not recursively permissive with elements of sequences and hashes. Bugfix: freemarker.ext.beans.MapModel returns BeansWrapper.wrap(null) instead of null for null values explicitly bound into the map. Bugfix: Fixed a subtle bug with property getters of classes implementing a type-parametrized interface. Bug fixed: A further corner case of [1939742].
2.3.13 Date of release: 2008-05-05
Changes on the FTL side New built-ins for rounding numbers: round, floor, ceiling. See more here...
Changes on the Java side [1898300], [1818742], [1780882]: Reworked template caching mechanism for radically improved concurrent performance, with help from Azul Systems engineers. (Achieved 20x speedup with Struts2 webapps on a 128-CPU Azul device compared to 2.3.12.) Also, template loading (including parsing) errors are now cached, improving performance in applications that often try to get missing templates. [1892546] Allow for custom TemplateLoader in FreemarkerServlet. Bug fixed: [1725107] Using the FreeMarker JSP taglib support with Servlet 2.4 may generates XML validation warnings. Bug fixed: [1939742] ConcurrentModificationException on accessing nonexistent SimpleHash entries in a loop Bug fixed: [1902012] IteratorModel eats exception causes Bug fixed: <#assign x></#assign> (empty nested content) has caused NullPointerException Bug fixed: [1926150] CachedTemplate should be serializable
2.3.12 Date of release: 2008-02-03
Changes on the Java side Bug fixed: [1857161] JSP SimpleTag support was broken in 2.3.11. In the templates, now you can conveniently call Java methods that use the Java 5 varargs feature (variable-length argument lists). Also the overloaded-method chooser logic now considers vararg methods more intelligently. Enum constants are now identified by their name() instead of by their toString() (because the latter can be overridden in subclasses). This doesn't affect the way enum constants are printed; of course that still uses toString(). Messages in parser exceptions now display the name of the template.
2.3.11 Date of release: 2007-12-04 This release contains several performance and usability improvements.
Changes on the FTL side Bug fixed: [1687248] Warning! This bugfix may breaks some templates! Fixed the bugs of the c built-in (?c) that sometimes caused whole numbers to be formatted with ``.0'' at the end (like: 1.0), and caused numbers sometimes formatted to exponential form (like 4E-20). From now whole numbers will never use decimal dot (not even if the wrapped number is a double; remember, the template language knows only a single numerical type), and exponential form will never be used either. Also, the maximum number of digits after the decimal dot was limited to 16, so numbers smaller than 1E-16 will be shown as 0.
Changes on the Java side FreeMarker now has much better JSP 2.0 and JSP 2.1 compliance. Most notably, the JSP 2.0 SimpleTag interface is now supported. Additionally, even when run in an environment that doesn't have its own JSP implementation, the FreeMarker JSP runtime will make available its own implementation of JspFactory and JspEngineInfo to tags when JSP 2.0 API JAR is available in classpath, as well as an implementation of JspApplicationContext when JSP 2.1 API JAR is available in classpath. A new model interface, TemplateDirectiveModel provides an easier paradigm for implementing user-defined directives than TemplateTransformModel did previously. TemplateTransformModel will be deprecated. FreeMarker now finds the Xalan-based XPath support included in Sun JRE/JDK 5 and 6, so no separate Xalan jar is required for the XPath support to work. (However, we recommend Jaxen over Xalan, as the FreeMarker XPath support is more complete with that. Of course for that the Jaxen jar is still needed.) Wrapping performance of BeansWrapper has been significantly improved by eliminating repetitive execution of various class tests. Note for BeansWrapper customizers: subclasses of BeansWrapper that previously overrode getInstance(Object, ModelFactory) method should now instead override getModelFactory(Class) to take advantage of this improvement. Overriding the old method still works, but it will not take advantage of the performance improvement. Memory footprint of a wrapper created by BeansWrapper has been reduced (by a size of one default-sized HashMap) until methods or indexed properties are accessed on it (simple properties can be accessed without increasing memory footprint). Rhino objects can be used in templates as scalars, numbers, and booleans, following the JavaScript conversion semantics for these types. .data_model is now a TemplatHashModelEx when possible. This means that the list of the data-model variable names usually can be get with .data_model?keys. FileTemplateLoader can now optionally allow following symlinks that point out of the base directory. It is disabled by default for backward compatibility. Bug fixed: [1670887] TaglibFactory taglib matching did not follow JSP 1.2 FCS. Bug fixed: [1754320] Bug in setXPathSupportClass prevented plugging in a user-supplied XPathSupport implementation. Bug fixed: [1803298] Parser error while parsing macro with loop variables Bug fixed: [1824122] Loading templates from JAR files could lead to leaking of file handles (due to a bug in the Java API implementation of Sun). Bug fixed: Cached template is now removed from the cache if the re-loading of the modified template file fails, so no staled template is served.
Documentation changes Substantial reworkings in the Template Authors's Guide (which was previously called Designer's Guide), especially in the Getting Started section. #{...} is documented as deprected construct from now. The "transform" term is now removed from the documentation. Instead the more general "user-defined directive" term is used, which encompasses macros, TemplateTransformModel-s and the new TemplateDirectiveModel-s, which are just different ways of implementing user-defined directives. Some more minor improvements in the Manual.
2.3.10 Date of release: 2007-04-20 This release contains several important bugfixes.
Changes on the Java side [1589245] MultiTemplateLoader clears its internal cached data (used for optimizing subsequent lookups of the same template) when Configuration.clearTemplateCache() is invoked. [1619257] A bug that caused an exception when strict_bean_model was used in a FreeMarker configuration Properties object or in the <#setting .../> directive has been fixed. [1685176] A bug that caused StackOverflowError in certain interactions of garbage collector with MRU cache under Sun's Java 6 JVM has been fixed. [1686955] When ResourceBundleModel constructs MessageFormat objects, it passes them its own locale. More info... [1691432] A bug that caused BeansWrapper.EXPOSE_SAFE to be no safer than BeansWrapper.EXPOSE_ALL has been fixed.
Changes on the FTL side [1628550] You can now use dateExp?string.full for formatting dates using Java built-in format java.util.Date.FULL More info...
2.3.9 Date of release: 2007-01-23 This release contains support for accessing JDK 1.5 enums and public fields of classes from the templates through the BeansWrapper.
Changes on the Java side BeansWrapper can now expose public fields of objects to the template if you call the setExposeFields(true) on it. More info... BeansWrapper can now pass any sequence model to Java methods expecting a java.util.Collection or a native Java array (including primitive arrays). More info... BeansWrapper can now pass any sequence and collection model to Java methods expecting a java.lang.Iterable. More info... BeansWrapper can now unwrap numeric models into correct target types when passing to Java methods expecting a primitive or boxed number. Use of various expert built-ins to manually coerce the types becomes mostly unnecessary. Fixed a bug where BeansWrapper would pass a java.util.Collection to a method expecting a java.util.Set in certain rare cases. More info... Support for JDK 1.5 enums in BeansWrapper and DefaultObjectWrapper. By calling the getEnumModels() method, you can retrieve a hash model that is keyed by class names and allows access to enumerated values. I.e. if you bind this hash model under name enums in the data-model, you can write expressions like enums["java.math.RoundingMode"].UP in the template. The enum values can be used as scalars and support equality and inequality comparisons. More info... freemarker.ext.rhino.RhinoWrapper now correctly translates Rhino Undefined instance, UniqueTag.NOT_FOUND, and UniqueTag.NULL to FreeMarker undefined value.
2.3.8 Date of release: 2006-07-09 This release substantially improves the JSP 2.0 compatibility. (For those who have seen the same points in 2.3.7: Sorry, the version history was incorrect... those JSP 2.0 related changes were not in the release yet.)
Changes on the Java side JSP support improvement: [1326058] Added support for DynamicAttributes (new in JSP 2.0) JSP support improvement: Added support for pushBody()/popBody() in FreemarkerPageContext JSP support improvement: Added support for getVariableResolver() (new in JSP 2.0). JSP support improvement: Added support for include(String, boolean) (new in JSP 2.0). JSP support improvement: Added support for getExpressionEvaluator() (new in JSP 2.0). However, it will need Apache commons-el in the class path, or else this method will not work (it's optional). Note that EL support is not needed in principle, since FreeMarker has it's own expression language. But some custom JSP 2 tags may still want to use this method, after all it's in the JSP 2 API.
2.3.7 Date of release: 2006-06-23 This release, compared to 2.3.7 RC1, contains new operators for handling null/missing variables, , the substring built-in, and some more bugfixes. Note that 2.3.7 RC1 has a long change log, so you may want to read that too.
Changes on the Java side The seq_contains built-in now handles TemplateCollectionModel-s as well. Bug fixed: In 2.3.7 RC1 FreemarkerServlet has always died with NullPointerException during initialization.
Changes on the FTL side 3 new operators were added for terser missing variable handling. These operators make the default, exists and if_exists built-ins deprecated. (The parser doesn't issue any warning messages when you use deprecated built-ins, and they are still working.): exp1!exp2 is near equivalent with exp1?default(exp2), also (exp1)!exp2 is near equivalent with (exp1)?default(exp2). The only difference is that this new operator doesn't evaluate the exp2 when the default value is not needed. exp1! is similar to exp1?if_exists, also (exp1)! is similar to (exp1)?if_exists. The difference is that with this new operator the default value is an empty string and an empty list and empty hash at the same time (multi-type variable), while with if_exists the default value was an empty string and an empty list and empty hash and boolean false and a transform that does nothing and ignores all parameters at the same time. exp1?? is equivalent with exp1?exists, also (exp1)?? is equivalent with with (exp1)?exists. New built-in: exp?substring(from, toExclusive), also callable as exp?substring(from). Getting substrings was possible for a long time like myString[from..toInclusive] and myString[from..]. This syntax is now deprecated for getting substrings (but it's still working), and instead you should use myString?substring(from, toExclusive) and myString?substring(from). Sequence (list) slices still has to be get with the old syntax, since substring only applies to strings. Please note that the ``to'' parameter is 1 greater with this new builtin, as it is an exclusive index. Further difference is that the substring built-in requires that the ``from'' index is less than or equal to the ``to'' index. So 0 length substrings are possible now, but not reversed substrings. Bug fixed: [1487694] malfunction when the recover directive has no nested content
2.3.7 RC1 Date of release: 2006-04-27 This release contains many bugfixes and some FreemarkerServlet related improvements. It's a Release Candidate, which means that it shouldn't be used in production environment yet. We recommend this release for development, however. Please test it.
Changes on the Java side FreemarkerServlet improvement: AllHttpScopesHashModel is now public, so you can add unlisted variables to the data-model. FreemarkerServlet improvement: When it throws a ServletException, the J2SE 1.4 cause exception is now set under J2SE 1.4. Bug fixed: [1469275] NullPointerException when using BeansWrapper with reloaded classes Bug fixed: [1449467] HttpSessionHashModel is not Serializable Bug fixed: [1435113] Error in BeanWrapper with indexed properties Bug fixed: [1411705] Acquisition bug in TemplateCache Bug fixed: [1459699] Tag syntax can't set with Configuration.setSetting(String, String) Bug fixed: [1473403] ReturnInstruction.Return should be public
Changes on the FTL side Bug fixed: [1463664]kup [/#noparse] is printed out
2.3.6 Date of release: 2006-03-15 Quick release that fixes a serious bug of 2.3.5, days after its release. So for the recently added new features please see the section of 2.3.5.
Changes on the Java side Bug fixed: In FreeMarker 2.3.5 only, when you read a bean property for the second time, FreeMarker will say that it's missing (null).
2.3.5 Date of release: 2006-03-11 This release was withdrawn because of a serious bug in it. Please don't use it! Of course, all new features of it are included in FreeMarker 2.3.6. A few new features and several bugfixes.
Changes on the FTL side Bug fixed: [1435847] Alternative syntax doesn't work for comments Bug fixed: With the new square bracket syntax, the tag could be closed with >. Now it can be closed with ] only. Bug fixed: [1324020] ParseException with the ftl directive if it wasn't in its own line Bug fixed: [1404033] eval built-in fails with hash concatenation
Changes on the Java side A new Configuration level setting, tagSyntax was added. This determines the syntax of the templates (angle bracket syntax VS square bracket syntax) that has no ftl directive in it. So now you can choose to use the new square bracket syntax by default. However, the recommended is to use auto-detection (yourConfig.setTagSyntax(Configuration.AUTO_DETECT_TAG_SYNTAX)), because that will be the default starting from 2.4. Auto-detection chooses syntax based on the syntax of the first FreeMarker tag of the template (could be any FreeMarker tag, not just ftl). Note that as with the previous version, if a the template uses ftl directive, then the syntax of the ftl directive determines the syntax of the template, and the tagSyntax setting is ignored. Now BeansWrapper, DefaultObjectWrapper and SimpleObjectWrapper support lookup with 1 character long strings in Map-s (like myHash["a"]) that use Character keys. Simply, as a special case, when a hash lookup fails on a string that is 1 character long, it checks for the Character key in the underlying map. (Bug tracker entry [1299045] FreeMarker doesn't support map lookup with Character keys.) A new property, strict was added to BeansWrapper, DefaultObjectWrapper and SimpleObjectWrapper. If this property is true then an attempt to read a bean propertly in the template (like myBean.aProperty) that doesn't exist in the bean class (as opposed to just holding null value) will cause InvalidPropertyException, which can't be suppressed in the template (not even with myBean.noSuchProperty?default('something')). This way ?default('something') and ?exists and similar built-ins can be used to handle existing properties whose value is null, without the risk of hiding typos in the property names. Typos will always cause error. But mind you, it goes against the basic approach of FreeMarker, so use this feature only if you really know what are you doing. Bug fixed: [1426227] NullPointerException in printStackTrace(...) Bug fixed: [1386193] Division by zero in ArithmeticEngine
2.3.4 Date of release: 2005-10-10 Some new features and bugfixes.
Changes on the FTL side Now you can use [ and ] instead of < and > for the FreeMarker tags. For example you can write [#if loggedIn]...[/#if] and [@myMacro /]. More info... Bugfix: the has_content built-in returned false for number, date and boolean values (if the value was not a multi-type value that is also a sequence or collection or hash or string). Now it always returns true for a number, date or boolean values (except if the value is also a sequence or collection or hash or string, because then it will be examined only like that).
Changes on the Java side Bugfix: the parameterless constructor of the ClassTemplateLoader didn't worked. Bugfix: The Jython wrapper didn't wrapped java.util.Date objects well. Now it wraps them with BeanWrapper to TemplateDateModel. Bugfix: the include directive was blamed when the included file had syntax error.
Other changes Minor Manual fixes.
2.3.3 Date of release: 2005-06-23 Some new features and lot of bugfixes. Attention: If you are using the Log4J logging, from now at least Log4J 1.2 is required. This is because of incompatible changes in the Log4J API. If you build FreeMarker yourself: from now at least JavaCC 3.2 (instead of JavaCC 2.1) and at least Ant 1.6.1 (instead of Ant 1.5.x) is required. This doesn't affect users who use the freemarker.jar comes with the distribution.
Changes on the FTL side New built-in for formatting numbers for ``computer audience'' as opposed to human audience: c. It should be used for numbers that must use Java language formatting regardless of the number format and locale settings, like for a database record ID used as the part of an URL or as invisible field value in a HTML form, or for printing CSS/JavaScript numerical literals. New built-in for the columnar/tabular displaying of sequences: chunk. The sequence slice and substring operators now allow the omitting of the last index, in which case it defaults to the index of the last sequence item or character. Example: products[2..]. (Also, numerical range literals now allow the omitting of the final number, in which case it defaults to infinity. Example: 5...) Bugfix: ?replace has worked forever if the string to replace was "".
Changes on the Java side New template loader: freemarker.cache.StringTemplateLoader. It uses a Map with Strings as its source of templates. See more in the JavaDoc. Experimental Rhino support: FreeMarker now comes with an experimental object wrapper for Rhino (Java ECMAScript implementation): freemarker.ext.rhino.RhinoWrapper Some new utility methods for SimpleXxx classes: SimpleHash.toMap(), SimpleSequence.toList(). Bugfix: FTL literals and any other SimpleSequnce-s, and SimpleHash-es now can be used as parameters to the FreeMarker-unaware Java methods that are exposed by DefaultWrapper or BeansWrapper. That is, the method parameters are automatically converted from TemplateTypeModel-s to java.util.Map and java.util.List respectively. Bugfix: The JSP support now works in JSP 2 compliant containers as well. No, it doesn't support the new features of JSP 2 yet, it's just that the JSP 1.2 taglib support has not worked in JSP 2 containers. Bugfix: The Configuration.setOutputEncoding and setURLEscapingCharset methods died with NullPointerException when you tried to set the setting value to null, which is legal for these settings. Bugfix: freemarker.template.utility.StringUtil.replace(...) has worked forever if the string to replace was "". Bugfix: The Log4J logging was updated to be compatible with the upcoming Log4J 1.3. Note that now FreeMarker will need at least Log4J 1.2. Bugfix: FreeMarker didn't built from the source code on J2SE 1.5, because of the introduction of the enum keyword. Bugfix: The return value of SimpleSequence.synchronizedWrapper() was not properly synchronized. Same with SimpleHash.synchronizedWrapper(). Bugfix: Problem with BeansWrapper and overridden bean methods/properties. (Details: bug-tracker entry #1217661 and #1166533) Bugfix: Can't access JSP taglibs if Request attribute is defined in the data-model (Details: bug-tracker entry #1202918). Bugfix: Various minor parser glitches were fixed.
Other changes Manual improvements, especially in the FAQ.
2.3.2 Date of release: 2005-01-22 Bugfix release.
Changes on the Java side Bugfix: If you use JSP taglibs in FreeMarker templates, FreeMarker possibly tried to get DTD-s from the Sun Web site because of a bug introduced with FreeMarker 2.3.1. This was a serious problem since if your server is offline or the Sun Web site becomes temporarily inaccessible the templates that are using JSP taglibs will possibly die with error. Bugfix: The DefaultObjectWrapper has ignored the value of the nullModel property. (Note that it's discouraged to use a ``null model''.)
2.3.1 Date of release: 2005-01-04 Maintenance (with some important new features) and bugfix release.
Possible backward compatibility issue There is a bugfix that may affect the behavior of you Web application if you use JSP tags in FreeMarker templates: FreeMarker's implementation of javax.servlet.jsp.PageContext.getSession() was incorrect. The getSession() method is a convenience method by which the custom tag can get the current HttpSession object (possibly null if there is no session). Till now, if the session didn't existed then it has created it automatically, so it never returned null. This was a bug, so starting from 2.3.1 it never creates the session, just returns null if it doesn't exist. The old incorrect behavior could cause page rendering to fail if the method is called after the page is partially flushed. But beware, the old behavior has possibly hidden some bugs of the Web application, where it forgot to create the session, so with the new correct behavior you may face malfunction caused by previously cloaked bugs of the Web application. (It's the task of the MVC Controller to create the session, except if the JSP tag that needs a session is written so it creates it automatically, but then it doesn't expects that getSession() will do it.)
Changes on the FTL side New built-in: url. This built-in can be used for URL escaping. Note, however, that to use this built-in conveniently, the software that encapsulates FreeMarker has to be 2.3.1 aware (programmers will find more info bellow...). New special variables: output_encoding and url_escaping_charset. Note, however, that to use these, the software that encapsulates FreeMarker has to be 2.3.1 aware (programmers will find more info bellow...). New built-ins for sequences: seq_contains, seq_index_of, seq_last_index_of. New built-ins for strings: left_pad, right_pad and contains. New directive: attempt/recover The js_string built-in now escapes > as \> (to avoid </script>). The sort and sort_by built-ins now can sort by date values. Also, sort_by built-in now can sort by the subvarible of a subvariable of a subvariable... etc. for any level depth. (Details...) freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER now prints more HTML-context-proof messages.
Changes on the Java side New setting: output_encoding. This setting is used for informing FreeMarker about the charset that the enclosing software (as a Web application framework) uses for the output of FreeMarker. It's undefined by default, and although it is not strictly required to set it, the enclosing software should do so. This setting must be set if templates want to use the new output_encoding special variable, and possibly if they want to use the new url built-in. Note that the FreeMarker API allows you to set settings for each template execution individually (look at Template.createProcessingEnvironment(...)). New setting: url_escaping_charset. This is the charset used for calculating the escaped parts (%XX) when you do URL escaping with the new url built-in. If it is not set, then the url built-in uses the value of the output_encoding setting, and if that's not set either, then the parameterless version of url built-in (${foo?url}) can't be used. Using the singleton (static) Configuration instance is clearly a bad practice, so related methods are now deprecated, and the Manual was adjusted, and the FreemarkerXmlTask was updated as well. The freemarker.template.utility.Constants class was added that contains various static final fields that store frequently used constant TemplateModel values, as EMPTY_SEQUENCE, ZERO, ...etc. When using SecurityManager with FreeMarker, accessing system properties may caused AccessControlException. Now such exceptions are catched and logged with warning level, and the default value of the property is returned. The needles InvocationTargetException is now removed from the exception cause trace in certain cases. Added a dirty hack that prints ServletException root cause in TemplateException's stack trace if that's the direct cause exception of the TemplateException, despite the poorly written ServletException class. Bugfix: FreeMarker's implementation of javax.servlet.jsp.PageContext.getSession() was incorrect. The getSession() method is a convenience method by which the custom tag can get the current HttpSession object (possibly null if there is no session). Till now, if the session didn't existed then it has created it automatically, so it never returned null. This was a bug, so starting from 2.3.1 it never creates the session, just returns null if it doesn't exist. The old incorrect behavior could cause page rendering to fail if the method is called after the page is partially flushed. But beware, the old behavior has possibly hidden some bugs of the Web application, where it forgot to create the session, so with the new correct behavior you may face malfunction caused by previously cloaked bugs of the Web application. (It's the task of the MVC Controller to create the session, except if the JSP tag that needs a session is written so it creates it automatically, but then it doesn't expects that getSession() will do it.) Bugfix: The BeansWrapper didn't always handled properly the case of a Java class having both a public static field and a public static method with the same name. Bugfix: SimpleMethodModel had incorrectly propagate exceptions sometimes, causing null pointer exception. Bugfix: The template execution may used outdated cached values when you have processed the same Environment for multiple times, and changed settings between the two processings. Note that this could happen only in single-thread environment, where such setting modifications are allowed. Bugfix: Some of the string built-ins has died with IndexOutOfBounds exception if the template author has forgotten to specify required parameters. Now they die with more helpful error messages. Bugfix: freemarker.ext.dom.NodeModel.equals(...) has died with null pointer exception if its argument was null. Bugfix: The cause exception of TemplateException-s was sometimes printed twice in stack traces with J2SE 1.4 or later. Bugfix: The StringUtil.FTLStringLiteralEnc(String) method was finished.
Other changes Fixes and improvements in the Manual and in the API JavaDoc.
The history of the releases before the final version
Differences between the preview release and final release Added a dirty hack that prints ServletException root cause in TemplateException's stack trace if that's the direct cause exception of the TemplateException, despite the poorly written ServletException class. Bugfix: freemarker.ext.dom.NodeModel.equals(...) has died with null pointer exception if its argument was null. Bugfix: The cause exception of TemplateException-s was sometimes printed twice in stack traces with J2SE 1.4 or later. More minor improvements in the Manual.
2.3 Date of release: 2004-June-15 FreeMarker 2.3 introduces numerous little new features and quality improvements compared to the 2.2.x series. The most notable improvements are the ability to define functions (methods) in templates, the ability to interpolate variables in string literals, the support for a variable number of macro parameters, and the more intelligent default object wrapper. Although none of the improvements is a drastic change, the 2.3.x series is not backward compatible with the 2.2.x series (see the list below), so you may choose to use it for new projects only. Probably the most ``loudly promoted'' new feature is the totally redesigned XML wrapper. With the new XML wrapper FreeMarker targets a new application domain, which is similar to the application domain of XSLT: transforming complex XML to whatever textual output. Although this subproject is young, it is definitely usable in practice. See the XML Processing Guide for more details.
Non backward-compatible changes! Since interpolations (${...} and #{...}) now work inside string literals, the character sequence ${ and #{ in string literals are reserved for that. So if you have something like <#set x = "${foo}">, then you have to replace it with <#set x = r"${foo}"> -- beware, escapes such as \n will not work in raw (r) strings. The default (initial) value of the strict_syntax setting has been changed from false to true. When strict_syntax is true, tags with old syntax as <include "foo.ftl"> will be considered as static text (so they go to the output as-is, like HTML tags do), and not as FTL tags. Such tags have to be rewritten to <#include "foo.ftl">, since only parts that starts with <#, </#, <@, or </@ count as FTL tags. Or, to recover the old transitional behavior, where both legacy and new tag syntax was recognized, you have to explicitly set strict_syntax to false: cfg.setStrictSyntaxMode(false). Also, for individual templates you can force the old behavior by starting the template with <#ftl strict_syntax=false>. (For more information about why strict syntax is better than old syntax read this...) Several classes were moved from the freemarker.template package, to the new freemarker.core package: "Normal" classes: ArithmeticEngine, Configurable, Environment Exceptions: InvalidReferenceException, NonBooleanException, NonNumericalException, NonStringException, ParseException, StopException Errors: TokenMgrError The main reason of the splitting of freemarker.template package was that the amount of "expert" public classes and interfaces grows too much, as we introduce API-s for third-party tools, such as debugging API. freemarker.template.TemplateMethodModel.exec now returns Object instead of TemplateModel. White-space stripping is now more aggressive as before: it always removes leading and trailing white-space if the line only contains FTL tags. (Earlier the white-space was not removed if the tag was <#include ...> or user-defined directive tag with empty directive syntax as <@myMacro/> (or its equivalents: <@myMacro></@myMacro> and <@myMacro></@>). Now white-space is removed in these cases as well.) Also, white-space sandwiched between two non-outputting elements, such as macro definitions, assignments, imports, or property settings, is now ignored. More information: The function directive is now used for defining methods. You should replace function with macro in your old templates. Note, however, that old function-s will still work if you don't use the return directive in them, and you invoke them with the deprecated the call directive. The expressions as, in, and using are now keywords in the template language and cannot be used as top-level variable names without square-bracket syntax. If, by some chance, you have top-level variables that use one of these names, you will have to rename them, or use the square-bracket syntax with the .vars special variable: .vars["in"]. The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the freemarker.template.utility.ObjectConstructor class to your template. (For example: myDataModel.put("objConstructor", new ObjectConstructor());, and then in the template you can do this: <#assign aList = objConstructor("java.util.ArrayList", 100)>) Changes to the FreemarkerServlet: The FreemarkerServlet uses ObjectWrapper.DEFAULT_WRAPPER by default instead of ObjectWrapper.BEANS_WRAPPER. What this means is that, by default, objects of type java.lang.String, java.lang.Number, java.util.List, and java.util.Map will be wrapped as TemplateModels via the classes SimpleScalar, SimpleNumber, SimpleSequence, and SimpleHash respectively. Thus, the java methods on those objects will not be available. The default wrapper implementation in FreeMarker 2.3 automatically knows how to wrap Jython objects, and also wraps org.w3c.dom.Node objects into instances of freemarker.ext.dom.NodeModel. The FreemarkerServlet base implementation no longer deduces the locale used for templates with HttpRequest.getLocale(). Rather, it simply delegates to the new protected method, deduceLocale. The default implementation of this method simply returns the value of configuration the locale setting.
Changes on the FTL side Interpolation in string literals. For convenience, interpolations are now supported in string literals. For example: <@message "Hello ${user}!" /> is the same as <@message "Hello " + user + "!" /> Raw string literals: In string literals prefixed with r, interpolations and escape sequences will not be interpreted as special tokens. For example: r"\n${x}" will be simply interpreted as the character sequence '\', 'n', '$', '{', 'x', '}', and not as line-feed and the value of the x variable. Method variables can be defined in FTL, with the function directive. Support for a variable number of macro parameters. If the last parameter in a macro declaration ends with ..., all extra parameters passed to the macro will be available via that parameter. For macros called with positional parameters, the parameter will be a sequence. For named parameters, the parameter will be a hash. Note that it all works with the new function directive as well. A new header parameter, strip_text, that removes all top-level text from a template. This is useful for ``include files'' to suppress newlines that separate the macro definitions. See ftl directive New special variable: .vars. This is useful to read top-level variables with square bracket syntax, for example .vars["name-with-hyphens"] and .vars[dynamicName]. macro and assignment directives now accept arbitrary destination variable name with quoted syntax. For example: <#macro "name-with-hyphens">... or <#assign "foo bar" = 123>. The ?keys and ?values hash built-ins now return sequences. In practical terms this means you can access their sizes or retrieve their subvariables by index, and use all of the sequence built-ins. (Note for the programmers: The TemplateHashModelEx interface has not been changed. Your old code will work. See the API documentation to see why.) Existence built-ins (?default, ?exists, etc.) are now working with sequence subvariables as well. Read the documentation of the default built-in for more information. White-space stripping is now more aggressive as before: it always removes leading and trailing white-space if the line only contains FTL tags. (Earlier the white-space was not removed if the tag was <#include ...> or user-defined directive tag with empty directive syntax as <@myMacro/> (or its equivalents: <@myMacro></@myMacro> and <@myMacro></@>). Now white-space is removed in these cases as well.) Also, top-level white-space that separates macro definitions and/or assignments is now ignored. More information: White-space stripping can be disabled for a single line with the nt directive (for No Trim). Hashes can be concatenated using the + operator. The keys in the hash on the right-hand side take precedence. New built-ins for Java and JavaScript string escaping: j_string and js_string The replace and split built-ins now support case-insensitive comparsion and regular expressions (J2SE 1.4+ only), and some other new options. More information can be found here. New built-in for regular expression matching (J2SE 1.4+ only): matches New built-in, eval, to evaluate a string as FTL expression. For example "1+2"?eval returns the number 3. New built-ins for Java and JavaScript string escaping: j_string and js_string New special variables to read the value of the locale setting: locale, lang. See more in the reference... New special variable to read the FreeMarker version number: version. See more in the reference... Tree new directives, recurse, visit and fallback, were introduced to support declarative node-tree processing. These are meant to be used typically (though not exclusively) for processing XML input. Together with this, a new variable type has been introduced, the node type. See the chapter on declarative XML processing for more details. The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the freemarker.template.utility.ObjectConstructor class to your template. (For example: myDataModel.put("objConstructor", new ObjectConstructor());, and then in the template you can do this: <#assign aList = objConstructor("java.util.ArrayList", 100)>) Variable names can contain @ anywhere (without using quote-bracket syntax). For example: <#assign x@@@ = 123> is valid. The expressions as, in, and using are now keywords in the template language and cannot be used as top-level variable names without square-bracket syntax (as .vars["in"]). New parameter to the ftl directive: attributes. The value of this attribute is a hash that associates arbitrary attributes (name-value pairs) to the template. The values of the attributes can be of any type (string, number, sequence... etc.). FreeMarker doesn't try to understand the meaning of the attributes. It's up to the application that encapsulates FreeMarker (as a Web application framework). Thus, the set of allowed attributes and their semantic is application (Web application framework) dependent. Other minor quality improvements...
Changes on the Java side Smarter default object wrapping: The default object wrapper is now freemarker.template.DefaultObjectWrapper, which falls back on wrapping arbitrary objects as beans using the freemarker.ext.beans.BeansWrapper. Also, it will wrap org.w3c.dom.Node objects with the new DOM wrapper. Also, it is aware of Jython objects, and will use freemarker.ext.jython.JythonWrapper if the object passed in is a Jython object. (We count it as a backward compatible change, since this new object wrapper wraps differently only those objects that the old wrapper was not able to wrap, so it has thrown exception.) freemarker.template.TemplateMethodModel.exec now returns Object instead of TemplateModel. The default (initial) value of the strict_syntax setting has been changed from false to true. When strict_syntax is true, tags with old syntax as <include "foo.ftl"> will be considered as static text (so they go to the output as-is, like HTML tags do), and not as FTL tags. Such tags have to be rewritten to <#include "foo.ftl">, since only parts that starts with <#, </#, <@, or </@ count as FTL tags. Or, to recover the old transitional behavior, where both legacy and new tag syntax was recognized, you have to explicitly set strict_syntax to false: cfg.setStrictSyntaxMode(false). Also, for individual templates you can force the old behavior by starting the template with <#ftl strict_syntax=false>. (For more information about why strict syntax is better than old syntax read this...) New CacheStorage implementation: freemarker.cache.MruCacheStorage. This cache storage implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum. When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specified maximum. freemarker.cache.SoftCachseStorage and StrongCachseStorage are deprected, MruCachseStorage is used everywhere instead. The default cache storage is now an MruCachseStorage object with 0 strong size, and infinite soft size. Configuration.setSetting for cache_storage now understands string values as "strong:200, soft:2000". For BeansWrapper generated models, you can now use the ${obj.method(args)} syntax to invoke methods whose return type is void. void methods now return TemplateModel.NOTHING as their return value. freemarker.template.SimpleHash now can wrap read-only Map-s, such as the map of HTTP request parameters in Servlet API. The TemplateNodeModel interface was introduced to support recursive processing of trees of nodes. Typically, this will be used in relation to XML. New package: freemarker.ext.dom. This contains the new XML wrapper, that supports the processing of XML documents using the visitor pattern (i.e. with <#visit ...> and similar directives), and to provide more convenient XML traversing as the legacy wrapper. See the XML processing guide for more details. New package: freemarker.core. Classes used by mostly power-users was moved here from the freemarker.template package. The main reason of the splitting of freemarker.template package was that the amount of "expert" public classes and interfaces grows too much, as we introduce API-s for third-party tools, such as debugging API. New package: freemarker.debug. This provides a debugging API, by which you can debug executing templates through network (RMI). You have to write the front-end (client), as the API is just the server side. For more information please read the JavaDoc of the freemarker.debug package. You can query the FreeMarker version number with static method Configuration.getVersionNumber(). Also, the Manifest.mf included in freemarker.jar now contains the FreeMarker version number, furthermore, executing it with java -jar freemarker.jar will print the version number to the stdout. Added a new protected FreemarkerServlet method: Configuration getConfiguration(). Date support is now labeled as final. (It was experimental earlier.) The BeansWrapper has been improved to prevent some security exceptions when introspecting. Other minor quality improvements and extensions...
Other changes Fixes and improvements in the Manual and in the API JavaDoc.
The history of the releases before the final version
Differences between the final release and Release Candidate 4 Added a new special variable to print the FreeMarker version number: version. See more in the reference... Minor documentation fixes and improvements.
Differences between the Release Candidate 4 and Release Candidate 3 The BeansWrapper has been improved to prevent some security exceptions when introspecting. The FreemarkerXmlTask has two new sub-tasks that can be used to prepare template execution with Jython scripts: prepareModel and prepareEnvironment. The jython sub-task is now deprecated, and does the same as prepareEnvironment. See the Java API documentation for more details. New special variable to read the FreeMarker version number: version. See more in the reference... Bugfix: Greater-than sign doesn't confuse the eval built-in anymore. Bugfix: The BeansWrapper now wrapps the null return values of methods appropriately. Bugfix: The FreemarkerXmlTask doesn't need Jython classes anymore, unless you really use Jython scripts. Several other bugfixes in the Jython related features. Bugfix: If the template exception handler has ignored the exception, errors occurring in interpolations inside FTL tags (e.g. <#if "foo${badVar}" != "foobar">) were handled in the same way as errors occuring in interpolations outside FTL tags. Thus, the directive call was not skipped, and the problematic interpolation was replaced with an empty string. (This was inconsistent with the behavior of <#if "foo"+badVar != "foobar">, which should be 100% equivalent with the previous example.) Bugfix: The FileTemplateLoader is now more robust when it receives paths that are malformed according the native file system. In the earlier version such paths sometimes caused unexpected IOException that aborted the searching for the template in further FileTemplateLoader-s when you use the MultiTemplateLoader.
Differences between the Release Candidate 3 and Release Candidate 2 Bugfix: Fixing a fatal bug in the template cache that was introduced with the latest cache ``bugfix''. The template cache has always reloaded the unchanged template when the update delay has been elapsed, until the template has been actually changed, in which case it has never reloaded the template anymore.
Differences between the Release Candidate 2 and Release Candidate 1 Bugfix: The template cache didn't reload the template when it was replaced with an older version. API JavaDoc fix: date/time related classes/interfaces were marked as experimental. They are not experimental. Minor site improvements.
Differences between the Release Candidate 1 and Preview 16 releases Warning! Non-backward-compatible change! The default (initial) value of the strict_syntax setting has been changed from false to true. When strict_syntax is true, tags with old syntax as <include "foo.ftl"> will be considered as static text (so they go to the output as-is, like HTML tags do), and not as FTL tags. Such tags have to be rewritten to <#include "foo.ftl">, since only parts that starts with <#, </#, <@, or </@ count as FTL tags. Or, to recover the old transitional behavior, where both legacy and new tag syntax was recognized, you have to explicitly set strict_syntax to false: cfg.setStrictSyntaxMode(false). Also, for individual templates you can force the old behavior by starting the template with <#ftl strict_syntax=false>. (For more information about why strict syntax is better than old syntax read this...) New parameter to the ftl directive: attributes. The value of this attribute is a hash that associates arbitrary attributes (name-value pairs) to the template. The values of the attributes can be of any type (string, number, sequence... etc.). FreeMarker doesn't try to understand the meaning of the attributes. It's up to the application that encapsulates FreeMarker (as a Web application framework). Thus, the set of allowed attributes and their semantic is application (Web application framework) dependent. Bugfix: freemarker.template.utility.DeepUnwrap unwrapped sequences to empty ArrayList-s. Bugfix: If you included/imported a template with */ in path (acquisition), and that template in turn itself included/imported another template with */ in path, it may failed. New methods to the freemarker.core.Environment: importLib(Template loadedTemplate, java.lang.String namespace), getTemplateForImporting(...), getTemplateForInclusion(...). Improvements in the java.io.IOException related error messages of the include and import directives. Minor improvements in the documentation.
Differences between the Preview 16 and Preview 15 releases New package: freemarker.debug. This provides a debugging API, by which you can debug executing templates through network (RMI). You have to write the front-end (client), as the API is just the server side. For more information please read the JavaDoc of the freemarker.debug package. (The debugging API is present for a while, just I forgot to announce it in the version history. Sorry for that.) Bugfix: With the new XML wrapper, @@markup and similar special keys: have returned <foo></foo> for empty elements instead of <foo />. Other than it was needlessly verbose, it has confused browsers if you generate HTML. have showed the attributes that have no explicitly given value in the original document, just a default value coming form the DTD. have forgot to put space before the system identifier in the <!DOCTYPE ...>. Bugfix: XPath with Jaxen has died with NullPointerException if the context was an empty node set. A bit more intelligent Xalan XPath error messages. Revoked fallback-to-classloader logic from the template cache. From now, if no XPath engine is available, and the hash key in an ``XML query'' can't be interpreted without XPath, an error will tell this clearly, rather than silently returning undefined variable (null). Bugfix: Some templates have caused the parser to die. Some other minor improvements here and there...
Differences between the Preview 15 and Preview 14 releases Bugfix: The new default template cache storage (MruCacheStorage) has started to continually fail with NullPointerException from a random point of time, usually when the memory usage was high in the JVM. Bugfix: In error messages, when the quoted FTL directive had nested content, that was quoted as well, so the quotation could be very long and expose nested lines needlessly.
Differences between the Preview 14 and Preview 13 releases freemarker.template.TemplateMethodModel.exec now returns Object instead of TemplateModel. Fixes and improvements for XPath with Jaxen (not Xalan). Non-node-set XPath expressions are now working. FreeMarker variables are accessible in XPath expressions with XPath variable references (e.g. doc["book/chapter[title=$currentTitle]"]). freemarker.cache.SoftCachseStorage and StrongCachseStorage is deprected. The more flexible MruCachseStorage is used instead everywhere. The default cache storage is now an MruCachseStorage object with 0 strong size, and infinite soft size. Configuration.setSetting for cache_storage now understands string values as "strong:200, soft:2000". Bugfix: freemarker.cache.MruCachseStorage has died with ClassCastException sometimes. New built-ins for Java and JavaScript string escaping: j_string and js_string freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER now prints more HTML-context-proof messages. You can query the FreeMarker version number with static method Configuration.getVersionNumber(). Also, the Manifest.mf included in freemarker.jar now contains the FreeMarker version number, furthermore, executing it with java -jar freemarker.jar will print the version number to the stdout. Added a new protected FreemarkerServlet method: Configuration getConfiguration(). Bugfix: FreeMarker has frozen on empty conditional blocks in certain contexts. Bugfix: Methods called twice on an object using the list directive, as parent.getChildren() with <#list parent.children as child> ...</#list>
Differences between the Preview 13 and Preview 12 releases White-space stripping is now more aggressive as before: it always removes leading and trailing white-space if the line only contains FTL tags. (Earlier the white-space was not removed if the tag was <#include ...> or user-defined directive tag with empty directive syntax as <@myMacro/> (or its equivalents: <@myMacro></@myMacro> and <@myMacro></@>). Now white-space is removed in these cases as well.) Also, top-level white-space that separates macro definitions and/or assignments is now ignored. More information: White-space stripping can be disabled for a single line with the nt directive (for No Trim). A new directive for the declarative XML processing: fallback freemarker.template.SimpleHash now can wrap read-only Map-s, such as the map of HTTP request parameters in Servlet API.
Differences between the Preview 12 and Preview 11 releases The only change between this and the previous preview release is that Preview 11 had a bug where DOM trees would never be garbage-collected.
Differences between the Preview 11 and Preview 10 releases Many XML related changes. Some of them are incompatible with the previous preview releases! For a more detailed explanation of how XML related features now work, see: Attention! Attribute queries such as foo.@bar now return sequences (similarly to child element queries and XPath queries), not single nodes. Because of the rule with node sequences of size 1, it is still good to write ${foo.@bar}, but built-ins such as ?exists, ?if_exists or ?default don't work as before. For example, instead of foo.@bar?default('black'), you now have to write foo.@bar[0]?default('black'). So if you have used existence built-ins with attributes, you have to find those occurrences in the templates and add that [0]. Attention! XML name-space handling has been totally reworked and is absolutely incompatible with pre 10. Don't worry about this if none of your XML input documents use you use xmlns attributes. Worry, though, if you have utilized the ``loose mode'', where only the local name of elements were compared, because that's now gone. Sorry... Attention! Special-keys @@ and @* now return a sequence of attribute nodes instead of the hash of them. Several hash keys are now working for node sequences that store multiple nodes. For example, to get the list of all para elements of all chapter-s, just write doc.book.chapter.para. Or, to get list of title attributes of all chapter-s write doc.book.chapter.@title. New special hash keys: **, @@start_tag, @@end_tag, @@attribute_markup, @@text, @@qname. ?parent for attribute nodes now returns the element node the attribute node belongs to. You can use Jaxen instead of Xalan for XPath expressions, if you call the static freemarker.ext.dom.NodeModel.useJaxenXPathSupport() method once. We plan to use Jaxen automatically instead of Xalan if it is available, just the Jaxen support is not fully functional yet. New special variable: .vars. This is useful to read top-level variables with square bracket syntax, for example .vars["name-with-hyphens"] and .vars[dynamicName]. New built-in, eval, to evaluate a string as FTL expression. For example "1+2"?eval returns the number 3. FreemarkerServlet now uses the configuration's locale setting, rather than Locale.getDefault(), to set the locale of the templates. Also, the signature of the deduceLocale method has been changed. We have a new (beta status) CacheStorage implementation: freemarker.cache.MruCacheStorage. This cache storage implements a two-level Most Recently Used cache. In the first level, items are strongly referenced up to the specified maximum. When the maximum is exceeded, the least recently used item is moved into the second level cache, where they are softly referenced, up to another specified maximum. You can plug to try it with cfg.setCacheStorage(new freemarker.cache.MruCacheStorage(maxStrongSize, maxSoftSize)).
Differences between the Preview 10 and Preview 9 releases The special key @@xmlns was removed in favor of a new FTL directive for the same purpose, <#xmlns...>. By default, the system is stricter about the use of namespace prefixes. In general, you must use a prefix to qualify subelements that are associated with an XML nampespace. You can do this with the new <#xmlns...> directive, but prefixes declared in the input XML doc will actually work with no declaration. Introduced a new special key called @@text that returns all the text nodes contained (recursively) in an element all concatenated together. Either Jaxen or Xalan can be used to provide XPath functionality. Prior versions only worked with Xalan. The FreemarkerServlet uses ObjectWrapper.DEFAULT_WRAPPER by default instead of ObjectWrapper.BEANS_WRAPPER. What this means is that, by default, objects of type java.lang.String, java.lang.Number, java.util.List, and java.util.Map will be wrapped as TemplateModels via the classes SimpleScalar, SimpleNumber, SimpleSequence, and SimpleHash respectively. Thus, the java methods on those objects will not be available. The default wrapper implementation in FreeMarker 2.3 automatically knows how to wrap Jython objects, and also wraps org.w3c.dom.Node objects into instances of freemarker.ext.dom.NodeModel. The FreemarkerServlet base implementation no longer deduces the locale to use from the HttpRequest.getLocale() hook. Rather, it simply delegates to a deduceLocale() hook that is overridable in subclasses. The base implementation simply uses Locale.getDefault()
Differences between the Preview 9 and Preview 8 releases Fixed bugs introduced with Preview 8: XPath, @@markup and @@nested_markup now works with the document node.
Differences between the Preview 8 and Preview 7 releases macro and assignment directives now accept arbitrary destination variable name with quoted syntax. For example: <#macro "foo-bar">... or <#assign "this+that" = 123>. This is important, because XML element names can contain hyphen, and it was not possible to define a handler macro for those elements, till now. Special key @@content was renamed to @@nested_markup. Fixed outdated XML related Manual parts (that were outdated even in Preview 7). Better parse-error messages. Minor bugfixes here and there...
Differences between the Preview 7 and Preview 6 releases Caching of XPath queries should lead to significant performance improvements for XML processing, at least when XPath is heavily used. Refinements in handling of XML namespaces in the XML processing functionality. The new strict_namespace_handling setting introduced in 2.3pre6 was removed. A general-purpose solution was arrived at that should make that configuration setting unnecessary. Special key @xmlns was renamed to @@xmlns. Reserved namespace prefix default was renamed to @@default. The ftl directive now accepts non-string types. New special keys were introduced for XML node wrappers in the freemarker.ext.dom package. The @@markup key returns the literal markup that make up that element and the @@content key returns all the element's markup excluding the opening and closing tags. Minor bugfixes here and there...
Differences between the Preview 6 and Preview 5 releases Existence built-ins (?default, ?exists, etc.) now work with sequence subvariables as well. Read the documentation of the default built-in for more information. The matches built-in now returns a sequence instead of a collection. Refinements in handling of XML namespaces in the XML processing functionality. A new setting, strict_namespace_handling was introduced. If this is set (it is off by default) any node-handling macro used in with the visit/recurse machinery must be from a macro library that declares in its ftl header that it handles the namespace in question. Minor bugfixes here and there...
Differences between the Preview 5 and Preview 4 releases The replace and split built-ins now support case-insensitive comparison and regular expressions (J2SE 1.4+ only), and some other new options. More information can be found here. New butilt-in for regular expression matching (J2SE 1.4+ only): matches Minor bugfixes here and there... Manual: More browser-safe HTML-s. More updated content.
Differences between the Preview 4 and Preview 3 releases Bugfix: with multi-type variables, + operator overload for hash type had higher precedence than the precedence of some older overloads. The API documentation was missing from the distribution tar.gz.
Differences between the Preview 3 and Preview 2 releases XML processing: Many various bugfixes, especially with the declarative processing. XML processing: the namespace_uri built-in, the xmlnsuri header parameter, and the TemplateNodeModel.getNodeNamespace method were renamed to node_namespace and getNodeNamespace respectively. XML processing: Better documentation. Especially, note: A new header parameter, strip_text, that removes all top-level text from a template. See ftl directive Support for a variable number of macro parameters. If the last parameter in a macro declaration ends with ..., all extra parameters passed to the macro will be available via that parameter. For macros called with positional parameters, the parameter will be a sequence. For named parameters, the parameter will be a hash. For BeansWrapper generated models, you can now use the ${obj.method(args)} syntax to invoke methods whose return type is void. void methods now return TemplateModel.NOTHING as their return value.
Differences between the Preview 2 and Preview 1 releases The freemarker.ext.dom.NodeModel API changed slightly. The setDocumentBuilder() method was changed to setDocumentBuilderFactory() because the older scheme was not thread-safe. The stripComments and stripPIs methods are renamed to The removeComments and removePIs, and are fixed now. A new method, simplify has been added. The expressions as, in, and using are now keywords in the template language and cannot be used as top-level variable names without square-bracket syntax (as .vars["in"]). If, by some chance, you have top-level variables that use one of these names, you will have to rename them (or use the square-bracket syntax). Sorry for the inconvenience. The ?new built-in, as it was implemented, was a security hole. Now, it only allows you to instantiate a java object that implements the freemarker.template.TemplateModel interface. If you want the functionality of the ?new built-in as it existed in prior versions, make available an instance of the new freemarker.template.utility.ObjectConstructor class to your template. The <#recurse> directive was broken. It did not work with a using clause. This is now fixed.
2.2.8 Date of release: 2004-June-15 Bugfix and maintenance release.
Changes on the FTL side Added a new special variable to print the FreeMarker version number: version. See more in the reference...
Changes on the Java side The BeansWrapper has been improved to prevent some security exceptions when introspecting. Bugfix: The FileTemplateLoader is now more robust when it receives paths that are malformed according the native file system. In the earlier version such paths sometimes caused unexpected IOException that aborted the searching for the template in further FileTemplateLoader-s when you use the MultiTemplateLoader. Some parts of the FreeMarker code has been marked as privileged code section, so you can grant extra privileges to FreeMarker when you use a security manager (this is a backporting from 2.3). See more here...
Other changes Minor documentation fixes and improvements.
2.2.7 Date of release: 2004-March-17 Important bugfix release.
Changes on the Java side Bugfix: Fixing a fatal bug in the template cache that was introduced with the latest cache ``bugfix''. The template cache has always reloaded the unchanged template when the update delay has been elapsed, until the template has been actually changed, in which case it has never reloaded the template anymore.
2.2.6 Date of release: 2004-March-13 Maintenance and bugfix release. Some of improvements are back-portings from FreeMarker 2.3rc1.
Changes on the FTL side New special variable: .vars. This is useful to read top-level variables with square bracket syntax, for example .vars["name-with-hyphens"] and .vars[dynamicName]. New built-ins for Java and JavaScript string escaping: j_string and js_string
Changes on the Java side Bugfix: The template cache didn't reload the template when it was replaced with an older version. Bugfix: freemarker.template.utility.DeepUnwrap unwrapped sequences to empty ArrayList-s. Bugfix: In error messages, when the quoted FTL directive had nested content, that was quoted as well, so the quotation could be very long and expose nested lines needlessly. freemarker.template.TemplateExceptionHandler.HTML_DEBUG_HANDLER now prints more HTML-context-proof messages. You can query the FreeMarker version number with static method Configuration.getVersionNumber(). Also, the Manifest.mf included in freemarker.jar now contains the FreeMarker version number, furthermore, executing it with java -jar freemarker.jar will print the version number to the stdout. Date support is now labeled as final. (It was experimental earlier.) There was no change since FreeMarker 2.2.1.
Other changes Fixes and improvements in the Manual and in the API JavaDoc. The documentation now works with the Eclipse help plugin (accessible in the ``Editor/IDE plugins'' section of the FreeMarker Web page). Minor site improvements.
2.2.5 Date of release: 2003-09-19 Maintenance and bugfix release.
Changes on the Java side Creating a Configuration instance using the default constructor no longer fails if the current directory is unreadable due to I/O problems, lack of security permissions, or any other exception.
2.2.4 Date of release: 2003-09-03 Maintenance and bugfix release.
Changes on the Java side Improvements to JSP taglib support. If some third party taglib didn't work for you with FreeMarker, maybe now it will. The JSP PageContext now implements forward and include methods. Accepting EVAL_PAGE as an alias to SKIP_BODY in return values from doStartTag. It's a common bug in some widespread tag libraries, and now FreeMarker is less strict and accepts it. Fixes for some rare problems regarding namespaces of macros.
Other changes Minor improvements to the documentation.
2.2.3 Date of release: 2003-07-19 Bugfix release.
Changes on the FTL side Added the is_date built-in. Bugfix: Various is_xxx built-ins were returning false when applied to undefined expressions. Now they correctly fail on them.
Changes on the Java side Bugfix: The JSP taglib support can now read JSP 1.2 compliant TLD XML files. Bugfix: The JSP taglib support now emits more helpful exception messages when the specified TLD XML file is not found (previously it threw a NullPointerException). Bugfix: The JSP taglib support now initializes a custom tag after its parent and page context is set as some tags expect them to be set when attribute setters are called. Bugfix: The BeansWrapper could fail to analyze classes under very rare circumstances due to a premature storage optimization.
2.2.2 Date of release: 2003-05-02 Bugfix release.
Changes on the Java side Bugfix: The _text key of the freemarker.ext.xml.NodeListModel was not returning the text of the element when used with W3C DOM trees. The classes are now built against JDK 1.2.2 classes, ensuring the binary compatibility of FreeMarker distribution with JDK 1.2.
2.2.1 Date of release: 2003-04-11 This version introduces important new features, such as the native FTL date/time type, and the auto-include and auto-import settings. The date/time support is experimental, but we hope it will not substantially change. We would like to label it as final ASAP, so we urge everybody to send feedback on this topic to the mailing lists.
Changes on the FTL side New scalar type: date. For more information read: , , interpolation, ?string built-in for dates
Changes on the Java side New TemplateModel subinterface: TemplateDateModel. For more information read auto-include and auto-import: With these new configuration level settings, you can include and import commonly used templates (usually collection of macro definitions) at the top of all templates, without actually typing <#include ...> or <#import ...> into the templates again and again. For more information please read the Java API documentation of Configuration New template method: createProcessingEnvironment. This method makes it possible for you to do some special initialization on the Environment before template processing, or to read the environment after template processing. For more information please read the Java API documentation. Changes to freemarker.ext.beans package: BeanModel, MapModel, and ResourceModel now implement TemplateHashModelEx. Bugfix: Configurable.setSettings(Properties) didn't removed redundant spaces/tabs at the end of property values.
2.2 Date of release: 2003-03-27 This release introduces some really important new features. Unfortunately, evolution was painful again; we have a few non-backward compatible changes (see below). Also, for those of you awaiting desired native date/time type, sorry, it is still not here (because of some internal chaos in the team... stand by, it's coming).
Non backward-compatible changes! Macros are now plain variables. This means that if you are unlucky and you have both a macro and another variable with the same name, now the variable will overwrite the macro, so your old template will malfunction. If you have a collection of common macros, you should use the new namespace feature to prevent accidental clashes with the variables used in the templates. With the introduction of the new namespace support, global and assign directives are no longer synonyms. assign creates a variable in the current namespace, while global creates variable that is visible from all namespaces (as if the variable would be in the data-model). Thus, the variable created with assign is more specific, and hides the variable of the same name created with global. As a result, if you use both global and assign mixed for the same variable in your templates, now they will malfunction. The solution is to search-and-replace all globals in your old templates with assign. The reserved hash root no longer exists as a predefined variable (we no longer have reserved variables). Use special variable expressions to achieve similar effects. However, we have no equivalent replacement for root because of the changes in the variable scopes caused by the introduction of namespaces. You may should use .globals or .namespace. The BeansWrapper no longer exposes native Java arrays, booleans, numbers, enumerations, iterators, and resource bundles as TemplateScalarModel. This way, number objects wrapped through BeansWrapper are subject to FreeMarker's number formatting machinery. Also, booleans can be formatted using the ?string built-in. The signature of Configuration.setServletContextForTemplateLoading has been changed: the first parameter is now Object instead of javax.servlet.ServletContext. Thus, you have to recompile your classes that call this method. The change was required to prevent class-loading failure when javax.servlet classes are not available and you would not call this method. This release introduces a parse-time white-space remover that strips some of the typical superfluous white-space around FreeMarker tags and comments. This feature is on by default! Most probably this will not cause problems if you generate white-space neutral output like HTML. But if it does cause undesirable reformatting in output you generate, you can disable it with config.setWhitespaceStripping(false). Also, you can enable/disable it on a per-template basis with the new ftl directive. Some new directives were introduced: nested, import, escape, noescape, t, rt, lt. This means that if you are unlucky and the text of your template contains something like <nested>, then that will be misinterpreted as a directive. To prevent this kind of problem in the future, we recommend everybody to switch from the old syntax to the new syntax (``strict syntax''). The strict syntax will be the the default syntax starting from some of the later releases anyway. We plan to release a conversion tool for converting old templates. For more information please read: The data-model created by the FreemarkerServlet now uses automatic scope discovery, so writing Application.attrName, Session.attrName, Request.attrName is no longer mandatory; it's enough to write attrName (for more information read this). This may break an old template if that rely on the non-existence of certain top-level variables. FreemarkerServlet now uses the encoding of the template file for the output, unless you specify the encoding in the ContentType init-param, such as text/html; charset=UTF-8. The format of template paths is now more restricted than before. The path must not use /, ./ and ../ and :// with other meaning as they have in URL paths (or in UN*X paths). The characters * and ? are reserved. Also, the template loader must not want paths starting with /. For more information please read: Till now TemplateTransformModel.getWriter has received null as parameter map if the transform was called without parameters. From now, it will receive an empty Map instead. Note that the previous API documentation didn't state that it always receives null if there are no parameters, so hopelessly only very few classes exploit this design mistake.
Changes in FTL (FreeMarker Template Language) User-defined directives: Transform and macro call syntax has been unified; they can be called in the same way, as user-defined directives. This also means that macros support named parameters and nested content (like the -- now deprecated -- transform directive did). For example, if you have a macro called sect, you may call it via <@sect title="Blah" style="modern">Blah blah...</@sect>. For more information read: Macros are now plain variables. This significantly simplifies FreeMarker semantics, while providing more flexibility; for example you can pass macros as parameters to other macros and transforms. As for the problem of clashing commonly-used-macro and variable names, we provide a more powerful solution: namespaces. Namespaces: Names-spaces are invaluable if you want to assemble collections (``libraries'') of macros and transforms (and other variables), and then use them in any template without worrying about accidental name clashes with the application specific and temporary variables, or with the variables of other collections you want to use in the same template. This is extremely important if FreeMarker users want to share their macro/transform collections. For more information read: With the introduction of namespaces our variable related terminology changed. As a result, assign is no longer synonymous with global. The assign directive has been undeprecated, and should be used instead of global almost everywhere. In the new approach assign creates variables in the current namespace, while global creates a variable that is visible from all namespaces (as if the variable were in the root of the data-model). A variable created with assign in the current namespace hides the variable of the same name that was created with global. ftl directive: With this directive you can give information about the template for FreeMarker, like the encoding (charset) of the template, the used FTL syntax variant, etc. Also, this directive helps you to write templates that are less dependent on FreeMarker configuration settings, also it helps third-party tools to identify and correctly parse FreeMarker templates. For more information see: ftl directive White-space stripping: FreeMarker now automatically removes some of the typical superfluous white-spaces around FreeMarker tags and comments, like the indentation spaces before- and line-break after <#if ...> tags. For more information read: New directive to apply a common ("escaping") expression to all interpolations in a block: escape. The name comes from the common usage of this directive for automatic HTML-escaping of interpolations. The new and preferred way of number formatting with string built-in is foo?string(format), instead of the less natural foo?string[format]. The string built-in works for boolean values. For example: ${spamFilter?string("enabled", "disabled")}. For more information read the reference. The default strings for outputting boolean value using the string built-in can be set using the boolean_format setting. Comments can be placed inside FTL tags and interpolations. For example: <#assign <#-- a comment --> x = 3> All letters and numbers are enabled in variable names, also $ is allowed (as in Java programming language). Thus you can use accents, Arabic letters, Chinese letters, etc. String literals can be quoted with apostrophe-quote. "foo" and 'foo' are equivalent. New string built-ins: index_of, last_index_of, starts_with, ends_with, replace, split, chop_linebreak, uncap_first. New sequence built-ins: sort, sort_by. New built-ins for experts to check the type of a variable. See: is_... built-ins New built-in for experts to create a variable of certain Java TemplateModel implementation. See: new built-in New built-in, namespace, to get the namespace of a macro. New expression type: special variable expression. To prevent backward compatibility problems when we introduce new predefined variables, from now special variable expressions are used to access them. New directives: t, rt and lt directives allow you to do explicit white-space removal in extreme FTL applications. For more information read the reference. assign, local and global now can capture the output generated be the nested template fragment into the variable. This deprecates capture_output transform. More information: assign directive reference Bulk assignments (as <#assign x=1, y=2, z=3>) no longer need colon to separate the assignments (as <#assign x=1 y=2 z=3>), although it is still allowed to preserve backward compatibility. Path that contains //: is considered as absolute path. include and transform directives no longer need a semicolon to separate the template or transform name from the parameter list, although it is still allowed to preserve backward compatibility. #-less tag syntax is deprecated (but still working). That is, you should write <#directive ...> instead of <directive ...>, and </#directive ...> instead of </directive ...>. For more info read: foreach is depreciated (but still working). Use list instead. Bugfix: Undefined variables in hash and sequence constructors (as [a, b, c]) didn't caused errors. Bugfix: String concatenation had performance problem if there was multiple concatenations chained, as: "a"+x+"a"+x+"a"+x+"a"+x+"a"+x.
Changes on the Java side Arbitrary JSP custom tags can be used as FreeMarker transforms in FreemarkerServlet-driven templates. More information: Various improvements for BeansWrapper: The BeansWrapper no longer exposes arbitrary objects as TemplateScalarModels, only java.lang.String and Character objects. This way, number objects wrapped through BeansWrapper are subject to FreeMarker's number formatting machinery. As a side effect, non-string and non-number objects that were previously accepted in equality and inequality operations (because they had a string representation) will now cause the engine to throw exception on comparison attempt. java.lang.Character objects are exposed as scalars through BeansWrapper. Experimental feature: With the setSimpleMapWrapper method of BeansWrapper you can configure it to wrap java.util.Map-s as TemplateHashModelEx-s, and do not expose the methods of the object. TransformControl interface (was experimental earlier): If the Writer returned by TemplateTransformModel.getWriter implements this interface, it can instruct the engine to skip or to repeat evaluation of the nested content, and gets notified about exceptions that are thrown during the nested content evaluation. Note that the onStart and afterBody methods now are allowed to throw IOException. For more information please read the API documentation. Localized lookup can be disabled with the new Configuration methods: set/getLocalizedLookup, clearTemplateCache The new interface freemarker.cache.CacheStorage allows users to plug custom template caching strategies with the cache_storage setting. The core package now ships with two implementations: SoftCacheStorage and StrongCacheStorage. For more information read: You can set settings with string name and string value with the new setSetting(String key, String value) method of Configurable super-classes (as Configuration). Also you can load settings from .properties file with the setSettings method. Other new Configuration methods: clearTemplateCache, clearSharedVariables, getTemplateLoader, and clone. Changes to TemplateTransformModel interface: getWriter can throw IOException, and can return null if the transform does not support body content. Till now TemplateTransformModel.getWriter has received null as parameter map if the transform was called without parameters. From now, it will receive an empty Map instead. Note that the previous API documentation didn't state that it always receives null if there are no parameters, so hopelessly only very few classes exploit this design mistake. Various improvements for FreemarkerServlet: The data-model now uses automatic scope discovery, so writing Application.attrName, Session.attrName, Request.attrName is no longer mandatory; it's enough to write attrName. For more information read this. FreemarkerServlet now uses the encoding of the template file for the output, unless you specify the encoding in the ContentType init-param, such as text/html; charset=UTF-8. All Configuration level settings can by set with Servlet init-params (template_exception_handler, locale, number_format, etc.). The object wrapper the servlet internally uses is now set as the default object wrapper for its Configuration instance. It no longer forces session creation for requests that don't belong to an existing session, improving scalability. JDOM independent XML-wrapping: freemarker.ext.xml.NodeListModel is a re-implementation of freemarker.ext.jdom.NodeListModel that does not rely on JDOM; you don't need JDOM .jar anymore. The new NodeListModel automatically uses W3C DOM, dom4j, or JDOM, depending on which library is available (that is, depending on what object do you pass to its constructor). Bugfix: WebappTemplateLoader: Template updating didn't worked correctly with Tomcat due the caching of resources. Now WebappTemplateLoader tries to access the resources directly as File, if it is possible, thus bypasses the caching. Various bug-fixes for FreemarkerServlet: The servlet now loads the correct template if it was called through RequestDispatcher.include. The caching of HttpServletRequest objects is now compliant with the servlet specification. TemplateExceptions was suppressed in certain situations resulting in half-rendered pages without error message. Bugfix: FreeMarker didn't work if the javax.servlet classes was not available, because Configuration explicitly referred to javax.servlet.ServletContext. Bugfix: classes may were not found if they was available only in the WEB-INF, and FreeMarker tried to load the class dynamically. Bugfix: the Template constructor (and thus Configuration.getTemplate) sometimes threw TokenMgrError (a non-checked exception) instead of ParseException.
Other changes The Web application related examples has been replaced.
The history of the releases before the final version
Differences between the final and RC2 releases You can load settings from .properties file with the setSettings method of Configuration and other Configurable subclasses. New string built-in: uncap_first Bugfix: When exposing an XML document to a template and accessing it with XPath using Jaxen a ClassCastException has occurred. Bugfix: The template cache has loaded templates with bad Configuration instance in certain situations if you use not the static default Configuration instance.
Differences between the RC2 and RC1 releases Non backward compatible change!: FreemarkerServlet now uses the encoding of the template file for the output, unless you specify the encoding in the ContentType init-param, such as text/html; charset=UTF-8. Non backward compatible change compared to RC1!: The capture_output transform creates variable in the current namespace (as assign directive) with the var parameter, not a global variable. The new and preferred way of number formatting with string built-in is foo?string(format), instead of the less natural foo?string[format]. The string built-in works for boolean values. For example: ${spamFilter?string("enabled", "disabled")}. For more information read the reference. The default strings for outputting boolean value using the string built-in can be set using the boolean_format setting. String literals can be quoted with apostrophe-quote. "foo" and 'foo' are equivalent. The new interface freemarker.cache.CacheStorage allows users to plug custom template caching strategies with the cache_storage setting. The core package now ships with two implementations: SoftCacheStorage and StrongCacheStorage. For more information read: You can set settings with string name and string value with the new setSetting(String key, String value) method of Configurable super-classes (as Configuration). Other new Configuration methods: getTemplateLoader, clone. assign, local and global now can capture the output generated be the nested template fragment into the variable. This deprecates capture_output transform. More information: assign directive reference Other new Configuration methods: getTemplateLoader, clone. Changes to TemplateTransformModel interface: getWriter can throw IOException, and can return null if the transform does not support body content. Till now TemplateTransformModel.getWriter has received null as parameter map if the transform was called without parameters. From now, it will receive an empty Map instead. Note that the previous API documentation didn't state that it always receives null if there are no parameters, so hopelessly only very few classes exploit this design mistake. Changes to TemplateControl interface: onStart and afterBody methods are now allowed to throw IOException. Path that contains //: is considered as absolute path. New string built-ins: index_of, last_index_of, starts_with, ends_with, replace, split, chop_linebreak. New sequence built-ins: sort, sort_by. All Configuration level settings can by set with Servlet init-params (template_exception_handler, locale, number_format, etc.). Bugfix: classes may were not found if they was available only in the WEB-INF, and FreeMarker tried to load the class dynamically. Bugfix: setLocalizedLookup(false) of Configuration was overridden when you have called setTemplateLoader. Bugfix: String concatenation had performance problem if there was multiple concatenations chained, as: "a"+x+"a"+x+"a"+x+"a"+x+"a"+x. Bugfix: white-space stripping was not worked with tags spanning over multiple lines. Bugfix: Removing several dependencies on JDK 1.3, so FreeMarker can be build for JDK 1.2.2.
Differences between the Preview 2 and RC1 releases ftl is now stricter, and does not allow custom parameters. To associate custom attributes to templates, we may add a new directive later, if there is a demand for it. escape directive does not affect numerical interpolations (#{...}) anymore, as it has caused errors with string escapes as ?html. The normalizeName method of freemarker.cache.TemplateLoader has been removed, because it has caused too many complications. Instead, normalization happens on a single point in the TempateCache. In consequence, FreeMarker is now stricter about the format of template paths, as things like /../ are interpreted by the core. Experimental feature: With the setSimpleMapWrapper method of BeansWrapper you can configure it to wrap java.util.Map-s as TemplateHashModelEx-s, and do not expose the methods of the object. New Configuration methods: set/getLocalizedLookup, clearTemplateCache, clearSharedVariables. More cleanups in the Environment API. Better JSP standard compliance: JSP page-scope variables are the global variables that were created in the template (not the variables of the data-model). JDOM independent XML-wrapping: freemarker.ext.xml.NodeListModel is a re-implementation of freemarker.ext.jdom.NodeListModel that does not rely on JDOM; you don't need JDOM .jar anymore. The new NodeListModel automatically uses W3C DOM, dom4j, or JDOM, depending on which library is available (that is, depending on what object do you pass to its constructor). Bugfix: WebappTemplateLoader: Template updating didn't worked correctly with Tomcat due the caching of resources. Now WebappTemplateLoader tries to access the resources directly as File, if it is possible, thus bypasses the caching. Bugfix: Templates loaded with MultiTemplateLoader subclasses was removed from the template cache after the template update delay has elapsed (5 seconds by default) even if the template file was unchanged. This can cause lot of extra load for a high-traffic server if you have many templates or if the template update delay was set to 0 second. Bugfix: Undefined variables in hash and sequence constructors (as [a, b, c]) didn't caused errors.
Differences between the Preview 1 and Preview 2 releases All 16-bit Unicode letters and numbers are allowed in identifiers, as well as the $ character (as in Java programming language). Thus you can use accented letters, Arabic letters, Chinese letters, etc. as identifiers in templates Macros now can create loop variables for the nested content. For more information read this. New directives: t, rt and lt directives allow you to do explicit white-space removal in extreme FTL applications. For more information read the reference. The syntax of assignment-with-namespace has changed from <#assign foo=123 namespace=myLib>) to <#assign foo=123 in myLib>, since the previous syntax was confusing because its similarity to a bulk-assignment. Bulk assignments (as <#assign x=1, y=2, z=3>) no longer need colon to separate the assignments (as <#assign x=1 y=2 z=3>), although it is still allowed to preserve backward compatibility. Positional parameter passing is supported for macro calls as shorthand form of normal named parameter passing. For more details read read the reference. New built-in, namespace, to get the namespace of the currently executing macro. TransformControl interface (was experimental earlier): If the Writer returned by TemplateTransformModel.getWriter implements this interface, it can instruct the engine to skip or to repeat evaluation of the nested content, and gets notified about exceptions that are thrown during the nested content evaluation. For more information please read the API documentation. Jython wrapper can now wrap arbitrary Java objects, not only PyObject-s. If an object is passed to the wrapper that is neither a TemplateModel, nor a PyObject, it is first coerced into a PyObject using Jython's own wrapping machinery, and then wrapped into a TemplateModel as any other PyObject. Some cleanups in the Environment API. The Web application related examples has been replaced. Bugfix: Templates loaded with URLTemplateLoader subclasses was removed from the template cache after the template update delay has elapsed (5 seconds by default) even if the template file was unchanged. This can cause lot of extra load for a high-traffic server if you have many templates or if the template update delay was set to 0 second. Bugfix: FreeMarkerServlet has thrown ServletException even if a debug TemplateException handler was in use (so you may got Error 500 page instead of debug information).
2.1.5 Date of release: 2003-02-08
Changes on the Java side Bugfix: Fixed a bug that forced the cache to frequently reload templates accessed through URL and multi template loaders: Templates loaded with URLTemplateLoader subclasses and MultiTemplateLoader was removed from the template cache after the template update delay has elapsed (5 seconds by default) even if the template file was unchanged. This can cause lot of extra load for a high-traffic server if you have many templates or if the template update delay was set to 0 second.) Bugfix: Many anomalies in the JythonWrapper were resolved, making the integration with Jython much smoother: Jython wrapper can now wrap arbitrary Java objects, not only PyObject-s. If an object is passed to the wrapper that is neither a TemplateModel, nor a PyObject, it is first coerced into a PyObject using Jython's own wrapping machinery, and then wrapped into a TemplateModel as any other PyObject.
2.1.4 Date of release: 2002-12-26
Changes on the Java side Bugfix: Log4J is now found when automatically discovering the logging library to use. Bugfix: An exception is no longer thrown in the static initializer of the Configuration if the directory specified in the "user.dir" system property is not readable.
2.1.3 Date of release: 2002-12-09
Changes on the FTL side Bugfix: cap_first built-in did what double built-in does.
Other changes The official extension of FreeMarker template files is ftl from now, not fm. (This is the name of the template language; FTL, for FreeMarker Template Language.) Of course you can use any extensions, since FreeMarker does not deal with the file extension. But we recommend ftl extension as default. Web application examples got tweaked again, as under JDK 1.4 a class in an explicit (named) package can no longer import classes from the default (unnamed) package. Our webapp example was using classes in the default package, they are now moved into named packages.
2.1.2 Date of release: 2002-11-28
Changes in FTL (FreeMarker Template Language) FreeMarkerServlet now has a setting for the Content-Type header of the response, defaulting to text/html. Previously it set no content type, which made it not play nicely when integrated with software that expected it (i.e. OpenSymphony SiteMesh). FreeMarkerServlet now works correctly when mapped to an URL extension instead of URL path prefix. You can emulate include directive call within Java code by calling Environment.include(templateName, charset, parse). Bugfix: When Template.process() was called from another template processing, it set currentEnvironment to null when it returned, thus crashed the parent template processing. Bugfix: the _descendant key in JDOM support incorrectly left the document root element out of the result when applied to a Document node. Bugfix: because we incorrectly assumed certain behavior of JDK 1.4 Beans introspector, calls to public interface methods on non-public classes that implement the interface were causing exceptions on JDK 1.4
Other changes Various minor supplements to the manual. Documentation HTML pages don't try to load the SourceForge logo from the Internet anymore. The default ant target is jar, not dist.
2.1.1 Date of release: 2002-11-04
Changes in FTL (FreeMarker Template Language) Multi-type variables that are both string and number or string and date are now output using their number or date value instead of the string value when used in the ${...} interpolation. This practically makes the string part of a string/number or a string/date variables useless. Bugfix: operator ``or'' (||) worked wrongly when its left operand was a composite expression (e.g. the second || in false || true || false; this was evaluated to false, but it should be true) Bugfix: Less-than sign inside comments confused the FTL parser (e.g. <#-- blah < blah -->); it commented out everything after the problematic comment. Bugfix: Comparing two numerical constants (e.g. 3 == 3) caused internal error in the FTL parser, and aborted template processing with error. Experimental date/time type support was removed, since it seems that this initial implementation was misguided. FreeMarker 2.2 will certainly support data/time.
Changes on the Java side Bugfix: Numbers wrapped with BEANS_WRAPPER was displayed with the toString() method of wrapped object. Now they are rendered according to the number_format setting, because multi-type variables that are both string and number are now output using their number value instead of the string value. Experimental date/time type support was removed, since it seems that this initial implementation was misguided. FreeMarker 2.2 will certainly support data/time.
2.1 Date of release: 2002-10-17 Templates and the Java API are not fully compatible with 2.0 releases. You will need to revisit existing code and templates, or use 2.1 for new projects only. Sorry for this inconvenience; FreeMarker has undergone some revolutionary changes since the 1.x series. We hope things will soon be sufficiently mature for us to offer (almost) backward-compatible releases. Note that there is a backward-compatibility flag that can be set via Configuration.setClassicCompatible(true) that causes the new FreeMarker to emulate most of FreeMarker 1.x's quirks.
Changes in FTL (FreeMarker Template Language) More strict, reveals accidental mistakes in the templates, prevents showing incorrect information when something went wrong: An attempt to access an undefined variable causes an error and aborts template processing (by default at least; see later). In earlier versions undefined variables were silently treated as empty (zero-length) strings. However, you can handle undefined variables in the template with some new built-ins. For example, ${foo?if_exists} is equivalent with the ${foo} of earlier versions. Another way of looking at this is that null values no longer exist from the viewpoint of a template designer. Anything referenced must be a defined variable. Note however that the programmer can configure FreeMarker so that it ignores certain errors (say, undefined variables), and continues template processing by skipping the problematic part. This ``loose'' policy should be used only for sites that don't show critical information. New variable type: boolean. Conditions in if/elseif and operands of logical operators (&&, ||, !) must be booleans. Empty strings are no longer treated as a logical false. Local and global variables. More info: Local variables for macros. You can create/replace local variables in macro definition bodies with the local directive You can create/replace global (non-local) variables with the global directive The include directive now by default treats the passed filename as being relative to the including template's path. To specify absolute template paths, you now have to prepend them with a slash. The include directive can now use the acquisition algorithm (familiar from the Zope system) to look up the template to include. Basically, if a template is not found where it is looked up first, it is looked up in parent directories. This is however not a default behavior, rather it is triggered by a new syntactic element. Strict syntax mode: Allows you to generate arbitrary SGML (XML) without worrying about clashes with FreeMarker directives. For more information read: Terse comments: you can use <#-- ... --> instead of <comment>...</comment> Directive that you can use to change the locale (and other settings) inside the template: setting Directive to explicitly flush the output buffer: flush The top-level (root) hash is available via the variable root, which is now a reserved name. The misnamed function directive has been renamed to macro. String literals support various new escape sequences, including UNICODE escapes (\xCODE) The compress directive is now more conservative in removing line breaks. Built-in to capitalize the first word: cap_first Built-in to generate on-the-fly templates: interpret stop directive has an optional parameter to describe the reason of termination Better error messages. New variable type: date. Date support is experimental. It can change substantially in the future. Keep this in mind if you use it.
Changes on the Java side ObjectWrapper: You can put non-TemplateModel objects directly into hashes, sequences and collections, and they will be automatically wrapped with the appropriate TemplateModel implementation. The API of objects that are exposed to templates (SimpleXXX) has been changed according to this, for example in SimpleHash the old put(String key, TemplateModel value) is now put(String key, Object object). Also, you can pass any kind of object as data-model to Template.process. The alternative reflection based ObjectWrapper can expose the members of any Java object automatically for the designer. More information: Object wrapping, Bean wrapper, Jython wrapper. The Configuration object was introduced as a central point to hold all your FreeMarker-related global settings, as well as commonly used variables that you want to have available from any template. Also it encapsulates the template cache and can be used to load templates. For more information read . TemplateLoader: pluggable template loader, separates caching from template loading TemplateNumberModel-s do not control their formatting anymore. They just store the data (i.e. a number). Number formatting is done by the FreeMarker core based on the locale and number_format settings. This logic applies to the new experimental date type as well. TemplateBooleanModel introduced: Only objects that implements this interface can be used as a boolean in true/false conditions. More info: TemplateDateModel introduced: objects that implements this interface are recognized as dates and can be locale-sensitively formatted. Date support is experimental in FreeMarker 2.1. It can change substantially in the future. Keep this in mind if you use it. The TemplateModelRoot interface was deprecated. As of FreeMarker 2.1, you can simply use any instance of TemplateHashModel instead. This actually is due to a significant architectural change. Variables set or defined in a template are stored in a separate Environment object that only exists while the template is being rendered. Thus, the template doesn't modify the root hash. Changes to transformations Completely rewritten TemplateTransformModel interface. More flexible, and does not impose output holding. More information: The transform directive now takes an optional set of key/value pairs. <transform myTransform; key1=value1, key2=value2 ...>. More information: transform directive The transforms that ship with the FreeMarker core are now available by default to all templates - i.e. <transform html_escape> will invoke the freemarker.template.utility.HtmlEscape transform. More information: User-defined TemplateModel objects now can access the runtime environment (read and set variables, get the current locale, etc.) using an Environment instance, which can be obtained by the static Environment.getCurrentEnvironment() method. As a result, TemplateScalarModel.getAsString has been changed: it has no locale parameter. TemplateExceptionHandler-s make it possible to define your own rules on what to do when a runtime error occurs (e.g. accessing a non existing variable) during template processing. For example, you can abort template processing (recommended for most sites), or skip the problematic statement and continue template processing (similar to old behavior). DebugMode has been removed, use TemplateExceptionHandler.DEBUG_HANDLER or HTML_DEBUG_HANDLER instead. Logging: FreeMarker logs certain events (runtime errors for example). For more information read . SimpleIterator was removed, but we provide a TemplateCollectionModel implementation: SimpleCollection. Arithmetic engine is pluggable (Configuration.setArithmeticEngine). The core distribution comes with two engines: ArithmeticEngine.BIGDECIMAL_ENGINE (the default) that converts all numbers to BigDecimal and then operates on them, and ArithmeticEngine.CONSERVATIVE_ENGINE that uses (more-or-less) the widening conversions of Java language, instead of converting everything to BigDecimal. Changes to freemarker.ext.beans package: The JavaBeans adapter layer has suffered several major changes. First, BeansWrapper is no longer a static utility class - you can now create instances of it, and every instance can have its own instance caching policy and security settings. These security settings are also new - you can now create JavaBeans wrappers that hide methods that are considered unsafe or inappropriate in a templating environment. By default, you can no longer call methods like System.exit() from the template (although you can manually turn off these safeguards). The StaticModel and StaticModels classes are gone; their functionality is now replaced with the BeansWrapper.getStaticModels() method. freemarker.ext.jython package: FreeMarker can now directly use Jython objects as data-models using the Jython wrapper. Changes to freemarker.ext.jdom package: The package now uses the Jaxen package instead of its predecessor, the werken.xpath package to evaluate XPath expressions. Since Jaxen is a successor to werken.xpath, this can be considered to be an upgrade. As a consequence, namespace prefixes are now recognized in XPath expressions and the overall XPath conformance is better. Better error reporting: If the processing of a template is aborted by a TemplateException being thrown, or using a <#stop> directive, FreeMarker will now output an execution trace with line and column numbers relative to the template source. The output is written to a simple Writer; no more PrintWriter. This redesign causes FreeMarker to no longer swallow IOExceptions during template processing. Various API cleanups, primarily the removing of superfluous constructor and method overloads.
Other changes Documentation has been rewritten from scratch
Differences between the RC1 and final release Added the support for date models and locale-sensitive date formatting. Date support is experimental in FreeMarker 2.1. It can change substantially in the future. Keep this in mind if you use it. Added the default built-in which makes it possible to specify default values for undefined expressions. SimpleIterator has been removed, SimpleCollection has been introduced Arithmetic engine is pluggable. The core now contains two arithmetic engines: ArithmeticEngine.BIGDECIMAL_ENGINE and ArithmeticEngine.CONSERVATIVE_ENGINE. BeansWrapper supports a new exposure level: EXPOSE_NOTHING Constants interface was removed. ..._WRAPPER constants have been moved from Constants to ObjectWrapper, EMPTY_STRING constant was moved to TemplateScalarModel, NOTHING constant was moved to TemplateModel, TRUE and FALSE constants were moved to TemplateBooleanModel. JAVABEANS_WRAPPER was renamed to BEANS_WRAPPER Configuration.get and put, putAll were renamed to getSharedVariable and setSharedVariable, setAllSharedVariables Configuration.getClassicCompatibility, setClassicCompatibility were renamed to isClassicCompatible, setClassicCompatible Template.process method overloads with useReflection parameter was removed. But now we have setObjectWrapper method in the Configuration, so you can set the preferred root-object wrapper there. Some superfluous method overloads were removed; these changes are backward compatible with RC1 Various minor JavaDoc and Manual improvements Bugfix: include directive has calculated the base path of relative paths wrongly Bugfix: We have accidentally used a J2SE 1.3 class, but FreeMarker 2.1 must able to run on J2SE 1.2
2.01 The main improvement is in error reporting. Now exceptions are much more informative since they come with complete line number and column information. The only API change between 2.0 and 2.01 was the elimination of the CacheListener/CacheEvent API. Now, if the updating of a template file fails, the exception is thrown back to the caller to handle. If you want logging to occur when a template file is updated successfully, you can override the logFileUpdate() method in FileTemplateCache.
2.0 FreeMarker 2.0 final was released on 18 April 2002. The changes with respect to the previous release, 2.0 RC3 are fairly minor.
Bugfixes There were a couple of bugs in handling null values, where Lazarus did not do the same thing as FreeMarker Classic. Traditionally, in FreeMarker, nulls were treated as being equivalent to an empty string in the appropriate context. At this point, to the best of our knowledge, there is backward compatibility with FreeMarker Classic in this respect. Literal strings can now include line breaks. This was a backward compatibility issue with FreeMarker Classic that has been fixed.
Changes to the Template language You can use the extra built-in of myString?web_safe to convert a string to its "web-safe" equivalent, where problematic characters such as '<' are converted to &lt;. In displaying numbers with a fractional part, the rendering apparatus now respects the decimal separator of the template's locale, so that, for example, in continental Europe, you would see 1,1 and in the U.S. locale, 1.1.
Changes to the API The getAsString() method in the TemplateScalarModel interface now takes a java.util.Locale as a parameter. For the most part, this is a hook for later use. In the default implementation, SimpleScalar, this parameter is unused. If you are implementing this interface yourself, your implementation may ignore the parameter. However, it will be appealing for certain implementations. The constructors of FileTemplateCache have changed. If you are using an absolute directory on the file system as the location of your templates, you need to pass in an instance of java.io.File to indicate the location. If you use the constructors that take a string, this is taken to mean relative to the classloader classpath.
Miscellany The ant build script build.xml now contains a target that builds a .war file containing the Hello, World and Guestbook examples. It builds a fmexamples.war. For example, if you are using Tomcat in its out-of-the-box configuration, you would place this under <TOMCAT_HOME>/webapps and then you would use http://localhost:8080/fmexamples/servlet/hello and http://localhost:8080/fmexamples/servlet/guestbook for the Hello, World and Guestbook examples respectively.
2.0 RC3 FreeMarker 2.0 RC3 was released on 11 April 2002. This release was primarily devoted to fixing bugs that were reported in RC2.
Bug Fixes Variables defined in an <include...> were not available in the enclosing page. This has been fixed. The JavaCC parser was not configured to handle Unicode input correctly. Now, Unicode support is working. There was a bug when comparing a number with null. It should have returned false, but threw an exception instead. This has been fixed.
Changes to the Template Language The syntax of the include directive has changed. To indicate an unparsed include file, you do as follows: <include "included.html" ; parsed="n" > You can also indicate the encoding of the included file this way: <include "included.html" ; encoding="ISO-8859-5"> The built-in myString?trim was added for trimming the leading and trailing white-space from strings.
API changes The TemplateEventAdapter machinery was taken out. This was never set up in a very useful manner and we anticipate that version 2.1 will have more complete support for logging events. The template caching mechanism was streamlined and simplified. The FileTemplateCache can now be configured to load files relative to a class loader, using the Class.getResource() call. This allows templates to be bundled up in .jar files or in a .war file for easy deployment of web-based apps.
2.0 RC2 FreeMarker 2.0 RC 2 was released on 4 April 2002. Here is a summary of changes wrt to the first release.
Changes to Template Language Certain built-in functionality is provided via a new operator, '?'. Thus, myList?size provides the number of elements in a list. Similarly, myString?length provides the length of a string, myString?upper_case puts the string all in capital letters, and myHash?keys provides a sequence containing the keys in the hash. See for list of all available built-ins. Numerical comparisons can now be made using the "natural" operators < and > but there are also "web-safe" alternatives, such as \lt and \gt, since the use of these characters may confuse HTML editors and parsers. Note that these changed between rc1 and rc2, they now start with a backslash. A little asymmetry is the fact that if you use the natural greater-than or greater-than-or-equals operators (i.e. > or >=) the expression must be in parentheses. With any other operator, the parentheses are optional. Within an iteration loop -- i.e. a foreach or a list block -- the current count in the loop is available as the special variable index_count. where index is the name of the variable in the iteration. A boolean variable called index_has_next is also defined that indicates whether there are any more items in the iteration after this one. Note that the index starts at zero, so you will often be adding one to it in practice. The <#break> directive can now be used to break out of a <#foreach...> or a <list...> loop. (Prior to this version, it only worked within a switch-case block.) There is a new directive called <#stop> that, when encountered, simply halts processing of the template. This can be useful for debugging purposes. When invoking java methods that have been exposed to the page, using the code in freemarker.ext.*, there are built-ins that allow you to indicate the numerical type that you wish to pass as the value. For instance, if you had two methods, one that takes an int and another that takes a long, and you wanted to pass in a value, you would have to specify which method. myMethod(1?int) or myMethod(1?long). This is unnecessary if there is only one method of the given name. Ranges can be used to get the sublist from a list or the substring of a string. For example: myList[0..3] will return items 0 through 3 of the list in question. Or, for example, you could get all the elements of the list except for the first and last ones via: myList[1..(myList?size-2)] Or we could get the first 6 characters of a string via myString[0..5] Lists can be concatenated using the '+' operator. Previously, this overloading of '+' only applied to strings. An attempt to compare a number to a string now throws an exception, since it is indicative of a coding error. Note that there is a backward compatibility mode that can be set (see below) that loosens this up in order to be able to process legacy templates.
API Changes The TemplateSequenceModel interface now has a size() method for getting the number of elements in the sequence in question. The TemplateModelIterator interface now has a hasNext() method. The default sequence and hash implementations, freemarker.template.SimpleSequence and freemarker.template.SimpleHash are now unsynchronized. If you need the methods to be synchronized, you can get a synchronized wrapper via the synchronizedWrapper() in either class. The freemarker.utility.ExtendedList and freemarker.utility.ExtendedHash classes were removed, since all of the extra keys that it defined are now available using the appropriate '?' built-in operation, i.e. myHash?keys or myList?size or myList?last. There is a method in java.freemarker.Configuration named setDebugMode() which allows you to decide whether stack traces are simply output to the web client (the best situation in development) or thrown back to the caller to be handled more gracefully (the best situation in production). There is a flag that can be set to turn on a processing mode that is more backward-compatible with FreeMarker Classic. This is off by default, but you can set it via Template.setClassicCompatibility(true). What this does is that it allows scalars to be treated as a single-item list in a list directive. Also, it allows somewhat more looseness about types. In FreeMarker 1.x, <#if x=="1"> and <#if x==1> were in fact equivalent. This meant that legacy templates might tend to be slack about this. If classic compatibility is not set, an attempt to compare the string "1" with the number 1 will result in an exception being thrown. (Note that it is preferable to get your templates working without the backward compatibility flag, since it usually will require only minor changes. However, for people with a lot of templates and no time to check over them, this flag may be of use.)
2.0 RC1 The first public release of FreeMarker 2.0 was on 18 March 2002. Here is a summary of the changes in the Lazarus release, with respect to the last stable release of FreeMarker Classic. NOTA BENE: Despite the changes delineated above, the Lazarus release is almost entirely backward-compatible with FreeMarker Classic. We believe that most existing code and templates that work under FreeMarker Classic will continue working under Lazarus, with at most minimal changes. In practice, the most common cases where legacy template code is broken will be where assumptions were made about numbers and strings being equivalent. Note that in FreeMarker 2, 2 + 2 does not result in "22". The String "1" and the number 1 are entirely different animals and thus, any code will be broken if it relies on the boolean expression ("1"==1) being true. There is a "classic compatibility mode" that can be set via: Template.setClassCompatibility() that can be set so that Lazarus emulates some of the quirky behavior of FreeMarker Classic. However, any code that relied on the above "features" of FreeMarker classic really should be reworked. You are less likely to run into the other incompatibilities that are listed above. If you come across any other anomalies, please do tell us about them.
Support for Numerical operations, both arithmetic and boolean, as well as numerical ranges. Scalars can now be either strings or numbers. (In FreeMarker Classic all scalars were strings.) The basic operations allowed are addition, subtraction, multiplication, division, and modulus using the +, -, *, /, and % operators respectively. Arbitrary-precision arithmetic with integers and floating point numbers are provided. Though our goal is definitely to follow the principle of least surprise, for backward compatibility, the + operator still is used for string concatenation. If either the left hand side or the right hand side of lhs + rhs is non-numerical, we revert to interpreting this as string concatenation. Thus, in FreeMarker 2, 2+2 evaluates to the number 4, while any of "2"+2 or 2+"2" or "2"+"2" evaluate to the string "22". In FreeMarker Classic, rather embarrassingly, all of the above, including 2+2, evaluated to the string "22". An attempt to use any other arithmetic operator besides the + with non-numerical operands will cause an exception to be thrown. Output of a numerical expression can be made explicit via the alternative #{....} syntax. If the expression within the curly parentheses does not evaluate to a numerical value, an exception is thrown. The older ${....} syntax can evaluate to either a number or a string. In general, if, for logical reasons, the output must be numerical, it is preferable to use the #{...} syntax, since it adds an extra sanity check. Note that if, by some miracle, the character sequence "#{" occurs in your template, you will have to use a workaround to prevent problems. (The <noparse> directive is one possibility.) In this release, there is a facility for specifying the number of digits to show after the decimal point. The following code specifies to show at least 3 digits after the decimal point but not more than 6. This is optional. This option is only available if you use the #{...} syntax. #{foo + bar ; m3M6} (Note that the above is something of a stopgap measure. Future releases will move toward supporting fully internationalization and localization of number and currency formatting. Numerical expressions can be used in boolean expressions via the comparison operators: lt, gt, lte, and gte. In the web space, where FreeMarker is most used in practice, using the more natural operators such as < and > would tend to confuse HTML-oriented editors. An attempt to compare non-numerical expressions using these operators leads to a TemplateException being thrown. If, by some coincidence, you have variables named "lt", "gt", "lte", or "gte", you will have to change their names, since they are now keywords in the language. Numerical ranges are supported. <#list 1990..2001 as year> blah blah in the year ${year} blah </#list> The left hand and right hand sides of the .. operator must be numerical, or an exception is thrown. They also need not be literal numbers, but can be more complex expressions that evaluate to a numerical scalar value. Note that it is also possible to write a range that descends in value: <#list 2001..1990 as year> blah blah in the year ${year} blah blah </#list>
API Changes The TemplateNumberModel interface and the SimpleNumber implementation were added to support exposing numerical values. The TemplateListModel API in FreeMarker Classic had some design problems -- particularly in terms of supporting thread-safe code. It has been deprecated in favor of the following API's: TemplateCollectionModel and TemplateSequenceModel. The SimpleList class was refactored to implement the above interfaces (and paradoxically, does not implement the TemplateListModel interface.) Code that uses the deprecated TemplateListModel should be refactored. The Expose Package by Attila Szegedi has been made an integral part of the FreeMarker distribution and is now under the freemarker.ext.* hierarchy. This package provides advanced models for representing arbitrary Java objects as template models, for representing XML documents as template models, as well as classes to facilitate the integration of FreeMarker with servlets and Ant. In FreeMarker Classic, there were some utility classes such as freemarker.template.utility.Addition etcetera that existed as workarounds for the lack of numerical operations in FreeMarker. Those have been removed and will probably not be missed. In FreeMarker Classic, the SimpleScalar object was mutable, it had a setValue method. This was fairly obviously a design mistake. Any code that relied on this must be refactored. Note that in this release, both SimpleScalar and the newly introduced SimpleNumber are both immutable and final.
Syntactical Miscellany The if-elseif-else syntax was introduced. FreeMarker classic only had if-else. This construct should probably (in the opinion of the author of this document -- Revusky) be used in preference to switch-case since the switch-case with fall-through is a notoriously error-prone construct for most mortal men. You can now do a multiple assignment in one <assign...> directive. For example: <assign x = 1, y = price*items, message="foo"> A scalar will no longer be interpreted as a one-item list in a <list...> or <#foreach...> block. If you have code that relied on this feature, there is an easy workaround, since you can simply define a list literal with exactly one item. <assign y=[x]> and then... <list y as item>...</list>
License license FreeMarker 1.x was released under the LGPL license. Later, by community consensus, we have switched over to a BSD-style license. As of FreeMarker 2.2pre1, the original author, Benjamin Geer, has relinquished the copyright in behalf of Visigoth Software Society. The current copyright holder is the Visigoth Software Society. ------------------------------------------------------------------------------ Copyright (c) 2003 The Visigoth Software Society. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The end-user documentation included with the redistribution, if any, must include the following acknowlegement: "This product includes software developed by the Visigoth Software Society (http://www.visigoths.org/)." Alternately, this acknowlegement may appear in the software itself, if and wherever such third-party acknowlegements normally appear. 3. Neither the name "FreeMarker", "Visigoth", nor any of the names of the project contributors may be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact visigoths@visigoths.org. 4. Products derived from this software may not be called "FreeMarker" or "Visigoth" nor may "FreeMarker" or "Visigoth" appear in their names without prior written permission of the Visigoth Software Society. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------ This software consists of voluntary contributions made by many individuals on behalf of the Visigoth Software Society. For more information on the Visigoth Software Society, please see http://www.visigoths.org/ ------------------------------------------------------------------------------ FREEMARKER SUBCOMPONENTS UNDER DIFFERENT LICENSE: FreeMarker includes a number of subcomponents that are licensed by the Apache Software Foundation under the Apache License, Version 2.0. Your use of these subcomponents is subject to the terms and conditions of the Apache License, Version 2.0. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 The subcomponents under this licence are the following files, which are included both in freemarker.jar and in the source code: freemarker/ext/jsp/web-app_2_2.dtd freemarker/ext/jsp/web-app_2_3.dtd freemarker/ext/jsp/web-app_2_4.xsd freemarker/ext/jsp/web-app_2_5.xsd freemarker/ext/jsp/web-jsptaglibrary_1_1.dtd freemarker/ext/jsp/web-jsptaglibrary_1_2.dtd freemarker/ext/jsp/web-jsptaglibrary_2_0.xsd freemarker/ext/jsp/web-jsptaglibrary_2_1.xsd
Start-tag Tag, which indicates that the following content is under the element, up to the end-tag. The start-tag may also specifies attributes for the element. An example of a start-tag: <body bgcolor=black> Boolean This is a variable type. A boolean variable represents a logical true or false (yes or no). For example, if the visitor has been logged in or not. There are only two possible boolean values: true and false. Typically, you will use booleans with an <#if ...> directive when you want to display text based on some condition, say, you show a certain part of the page only for visitors who has logged in. Character A symbol that people use in writing. Examples of characters: Latin capital letter A (``A''), Latin small letter A (``a''), digit four (``4''), number sign (``#''), colon (``:'') Charset A charset is a rule (algorithm) for transforming a sequence of characters (text) to a sequence of bits (or in practice, to a sequence of bytes). Whenever a character sequence is stored on a digital media, or sent through a digital channel (network), a charset must be applied. Examples of charsets are ISO-8859-1, ISO-8859-6, Shift_JIS , UTF-8. The capabilities of different charsers are different, that is, not all charsets can be used for all languages. For example ISO-8859-1 can't represent Arabic letters, but ISO-8859-6 can, however it can't represent the accented letters that that ISO-8859-1 can. Most charsets are highly restrictive regarding the allowed characters. UTF-8 allows virtually all possible characters, but most text editors can't handle it yet (2004). When different software components exchange text (as the HTTP server and the browser, or the text editor you use for saving templates and FreeMarker who loads them), it's very important that they agree in the charset used for the binary encoding of the text. If they don't, then the binary data will be misinterpreted by the receiver (loader) component, which usually results in the distortion of the non-English letters. Output encoding Means output charset. In the Java world the term ``encoding'' is commonly (mis)used as a synonym to ``charset''. Template encoding Means template charset. In the Java world the term ``encoding'' is commonly (mis)used as a synonym to ``charset''. Collection A variable that (in conjunction with the list directive) can spit out a series of variables. Data-model Something that holds the information the template has to show (or use in some other ways) when the template processor assembles the output (e.g. a Web page). In FreeMarker this is best visualized as a tree. Directive Instructions to FreeMarker used in FTL templates. They are invoked by FTL tags. Element Elements are the most fundamental building pieces of SGML documents; an SGML document is basically a tree of elements. Example of elements used in HTML: body, head, title, p, h1, h2. End-tag Tag, which indicates that the following content is not under the element. Example: </body>. Environment An Environment object stores the runtime state of a single template template processing job. That is, for each Template.process(...) call, an Environment instance will be created, and then discarded when process returns. This object stores the set of temporary variables created by the template, the value of settings set by the template, the reference to the data-model root, etc. Everything that is needed to fulfill the template processing job. Extensible Markup Language A subset (restricted version) of SGML. This is less powerful than SGML, but it easier to learn and much easier to process with programs. If you are an HTML author: XML documents are similar to HTML documents, but the XML standard doesn't specify the usable elements. XML is a much more general-purpose thing than HTML. For example you can use XML to describe Web pages (like HTML) or to describe non-visual information like a phone book database. SGML FreeMarker Template Language Simple programming language designed to write text file templates, especially HTML templates. FTL FTL tag Tag-like text fragment used to invoke FreeMarker directives in FTL templates. These are similar to HTML or XML tags at the first glance. The most prominent difference is that the tag name is started with # or @. Another important difference is that FTL tags do not use attributes, but a substantially different syntax to specify parameters. Examples of FTL tags: <#if newUser>, </#if>, <@menuitem title="Projects" link="projects.html"/> Hash A variable that acts as a container that stores subvariables that can be retrieved via a string that is a lookup name. Line break Line break is a special character (or a sequence of special characters) that causes a line breaking when you see the text as plain text (say, when you read the text with Windows notepad). Typically you type this character by hitting ENTER or RETURN key. The line break is represented with different characters on different platforms (to cause incompatibility and confusion...): ``line feed'' character on UNIX-es, ``carriage return'' character on Macintosh, ``carriage return''+``line feed'' (two characters!) on Windows and DOS. Note that line breaks in HTML do not have a visual effect when viewed in a browser; you must use markup such as <BR> for that. This manual never means <BR> when it says ``line-break''. Macro definition body The template fragment between the <#macro ...> and </#macro>. This template fragment will be executed when you call the macro (for example as <@myMacro/>). Method A variable that calculates something based on parameters you give, and returns the result. MVC pattern MVC stands for Model View Controller. It's a design pattern started his life in the 70's as a framework developer by Trygve Reenskaug for Smalltalk, and was used primary for for UI-s (user interfaces). MVC considers three roles: Model: Model represents application (domain) specific information in a non-visual way. For example, an array of product objects in the memory of your computer is the part of the model. View: View displays the model and provides UI. For example, it's the task of the view component to render the array of product objects to a HTML page. Controller: The controller handles user input, modifies the model, and ensures that the view is updated when needed. For example it is the task of controller to take the incoming HTTP requests, parse the received parameters (forms), dispatch the requests to the proper business logic object, and chose the right template for the HTTP response. The most important thing for us when applying MVC for Web applications is the separation of View from the other two roles. This allows the separation of designers (HTML authors) from programmers. Designers deal with the visual aspects, programmers deal with the application logic and other technical issues; everybody works on what he is good at. Designers and programmers are less dependent on each other. Designers can change the appearance without programmers having to change or recompile the program. For more information I recommend reading chapter 4.4 of Designing Enterprise Applications with the J2EE Platform blueprint. Predefined directive Directive what is defined by FreeMarker, thus always available. Example of predefined directives: if, list, include Scalar A scalar variable stores a single value. A scalar is either a string or a number or a date/time or a boolean. Sequence A sequence is a variable that contains a sequence of subvariables. The sequence's subvariables are accessible via numerical index, where the index of the very first object is 0, the index of the second objects is 1, the index of the third object is 2, etc. Regular expression A regular expression is a string that specifies a set of strings that matches it. For example, the regular expression "fo*" matches "f", "fo", "foo", etc. Regular expressions are used in several languages and other tools. In FreeMarker, the usage of them is a ``power user'' option. So if you have never used them before, there is no need to worry about not being familiar with them. But if you are interested in regular expressions, you can find several Web pages and books about them. FreeMarker uses the variation of regular expressions described at: http://java.sun.com/j2se/1.4.1/docs/api/java/util/regex/Pattern.html SGML Standard Generalized Markup Language This is an international standard (ISO 8879) that specifies the rules for the creation of platform-independent markup languages. HTML is a markup language created with SGML. XML is a subset (restricted version) of SGML. XML String A sequence of characters such as ``m'', ``o'', ``u'', ``s'', ``e''. Tag Text fragment indicating the usage of an element in SGML. Examples of tags: <body bgcolor=black>, </body> Template A template is a text file with some special character sequences embedded into it. A template processor (e.g. FreeMarker) will interpret special character sequences and it outputs a more or less different text from the original text file, where the differences are often based on a data-model. Thus, the original text acts as a template of the possible outputs. Template processing job A template processing job is the act when FreeMarker merges a template with a data-model to produce the output for a visitor. Note that this may includes the execution of multiple template files because the template file used for the Web page may invokes other templates with include and import directives. Each template-processing job is a separated cosmos that exists only for the short period of time while the given page is being rendered for the visitor, and then it vanishes with all the variables created in the templates (for example, variables created with assign, macro or global directives). Transform This term refers to user-defined directives that are implemetned with the now obsolete TemplateTransformModel Java interface. The feature was originally made for implementing output filters, hence the name. Thread-safe An object is thread-safe if it is safe to call its methods from multiple threads, even in parallel (i.e. multiple threads execute the methods of the object at the same time). Non-thread-safe objects may behave unpredictably in this situation, and generate wrong results, corrupt internal data structures, etc. Thread-safety is typically achieved in two ways with Java: with the usage synchronized statement (or synchronized methods), and with the immutability of encapsulated data (i.e. you can't modify the field after you have created the object). User-defined directive Directive that is not defined by the FreeMarker core, but by the user. These are typically application domain specific directives, like pull-down menu generation directives, HTML form handling directives. UCS This is international standard (ISO-10646) that defines a huge set of characters and assigns a unique number for each character (``!'' is 33, ..., ``A'' is 61, ``B'' is 62, ..., Arabic letter hamza is 1569... etc.). This character set (not charset) contains almost all characters used today (Latin alphabet, Cyrillic alphabet, Chinese letters, etc.). The idea behind UCS is that we can specify any character with a unique number, not mater what the platform or the language is. Unicode De-facto standard developed by Unicode organization. It deals with the classification of the characters in UCS (which is letter, which is digit, which is uppercase, which is lowercase, etc.), and with other problems of processing text made from the characters of UCS (e.g. normalization). White-space Characters that are totally transparent but have impact on the visual appearance of the text. Examples of white-space characters: space, tab (horizontal and vertical), line breaks (CR and LF), form feed. XML Attribute In connection with XML or HTML (or SGML in general), attributes are the named values associated with elements. For example, in <body bgcolor=black text=green>...</body>, the attributes are bgcolor=black and text=green. On the left side of = is the name of the attribute, while on the right side is the value of the attribute. Note that in XML, the values must be quoted (for example: <body bgcolor="black" text='green'>), while in HTML it is optional for certain values. Full-qualified name ... of nodes (XML node or other FTL node variable): The full-qualified name of a node specifies not only the node name (node?node_name), but also the node namespace (node?node_namespace), this way it unambiguously identify a certain kind of node. The format of the full-qualified name is nodeName or prefix:nodeName. The prefix is shorthand to identify the node namespace (the a node namespace is usually specified with a long ugly URI). In FTL, prefixes are associated with the node namespaces with the ns_prefixes parameter of the ftl directive. In XML files, prefixes are associated with the node namespaces with the xmlns:prefix attributes. The lack of the prefix means that the node uses the default node namespace, if a default node namespace is defined; otherwise it means that the node does not belong to any node namespace. The default node namespace is defined in FTL by registering reserved prefix D with the ns_prefixes parameter of the ftl directive. In XML files it is defined with attribute xmlns. ... of Java classes: The full-qualified name of a Java class contains both the class name and the name of the package the class belongs to. This way it unambiguously specifies the class, regardless of the context. An example of full-qualifed class name: java.util.Map (as opposed to Map). Alphabetical Index
libfreemarker-java-2.3.19.orig/src/manual/docgen-originals/0000755000175000017500000000000011723544471023126 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/manual/docgen-originals/figures/0000755000175000017500000000000012164627123024566 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/manual/docgen-originals/figures/model2sketch_with_alpha.png0000644000175000017500000017002711723544471032073 0ustar ebourgebourg‰PNG  IHDRXr5˜+tEXtCreation TimeH 30 dec. 2002 11:58:10 +0100@(8tIMEÒ  ‘ï Ž pHYs ð ðB¬4˜gAMA± üaïoIDATxÚìxUEÓÇ' !$„Þ»¡I—Þ»H/‚ ˆŠ‚bA± ØiŸ¾‚Ê+¯ Tª*¨ Ò ˆ H•ÞAz i$ùö¿É\7›sÓ˽d~yöɽçìéçžýŸ™ÙY"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/Á'»w@ÁÃp÷\ŒÍîÁ{%‚ðï³ÐÇ(&±VAHX‚ ätXPù…§±˜Š‰/±ÆZ‚ ‚ @Dù©RI•U9HqÂ)J•íª¼¥JEUò«’W•<ªä¢E˜ ‚ ‚`ÀV«Æª\¡Än@.GU©­JaUòQb‘åTœ¶•ÒºIíoj·#‚ ‚¥@€@(­¥8!µT•[U©¬J UîPå·øy_ªRF•¢”Pd9XÄ|­â—L][9-ï—Šíø9¬[„,D~t‚ äT > FBãÿפ¸ø*úW””Pe…*WU¹E•0UÂU‰T%šâÄ— ï.ÞϨÃp;¦ËZ±”Ø"•ÔvL×¥¹n‰„,Æ7»w@!0-EÿÄO+EqB‹ Ô1гf5¤ãµP`ÅzS•}'º»õº*…T P%7Å µÈøËØU~Våš*[)Î ÆõØêô7ÅÅUŸŽõ½•†í|oÌ3-Y‚ ‚ ™»!r¥8ËÎUÞQå.UêQœ°º™âÄ܆v/§JŠ €wŠ×‚€‚+±ÅÅlñôMñÿg«²:þs—øzKlíâ§/_¶l:¶óiü¼‚ªQœØò#Y‚ ‚ d"¦À* ÊUÑ¿BÖ¢uª<¯J5UB(NX•Ve\| 'Š ÀnSå—øé/пbŒ×7G•Zñëz(~ÚôøõbCÇO¿ì«ñß‹_µn§:ÅõŠÄþ–ˆ?>30_„,@ÞfAȉ°{.4Xw). â°Ð«°‰*ÍT Ve·*w«rN•ëgaª?ÿ*ýk‚% ñZUyâ\vÇo¯»*'(.Šâ×ÁÓžâbÀàŽ„õ ñ]mâ÷í›øí´¦¸^Ž, &³ôzŒŠŸ¡—dDü´cAÈDre÷‚ d#f 9Ä„Ê^U>§8ñÕ_•U«ÊŠ85ã—]ïfp-æ¡„Ö¢Ó÷¼…Șš§Ê“'Ò~T¥ÅõP|ƒþí%ÈÛY—ŠíœŠ_öºq\f€»¹ B!æbAr*°b]Tå2ÅÅ1Aø°å‡­?sãëv 8KUî¬V/«.{ XÈ}ÿ½ÅY¿zÄO_BÿZÄÒºc;Ñ”Pd ‚EˆK„œ ¸åZª2P•©ô¯ûŒ­?eâ¿C¬po¼ýãÔ•â\z¦Âr5¹(±+ŽEDÜ…«Té¬Ê4UºQ\®+ñ답¶A _ˆÝm‡S8ÄÄÏ7E–X°!  – 9<ÿÞŽÿü’*£(®· ¦£çâ°¦ÄÏ_Lÿ ¬åñÓì^*þ3â·zQ\z„±”X̰‰,d³(N !Ö*OükÑÖvJ¤b;¦°Š&V‚-H» 9N2 ÷ÚxUO¢.‚܇R\@{Lü2H·p³C]Ôy€âòUAHý?i¢ãçGĆ{q\HÇkU¿øºG`¼ÿ" ÛÁò°„!¸=<~{×I‚Û!K – 9¶ìŒQåNг qÒQ$…øBÂKô¯eŸïUå#UŽÇ×G,×wª ¦8ÑÃÖ#2ÖÿŸ „ÏìøùˆõbëÇ€!a芄:5Û‘Ø+AðÄ‚%BN„Çî3Ó4˜ 9íÌç¦ø¹?- ¾p¶t³Þu«.÷ìCà<[°|â—Ŷóį#&~~Düg¿øy”0YhrÛ1­WÜsQ„– d!ä.BN„­W¦Haáb¤lŒGÑ¿V(ã;uc SØp0:‹!XDÿ¦ûu8g•¯±Î€Tl‡§‰K² X‚ äDX8A¬\7¦á3'ô4Uf1cÆ2A„E9Ô·S$ý+Ö¢¬éÑÆº}–õ5æGﬔl‡çI» d"°AÈ©°HáÏ,°XÄøó¢)a¯<àKÿ #3UCŒU¸.¯Ç´*ÅÓ}­åbã÷!ÚØ¯´lGÄ• dƒ%BN‡‡ÍÁS\™+Æúo.çk|çú¦x3±3ªûXÅÔÙœçK‰÷+©íˆÀ„lDÖ…O*§ ‚‡-tlÜ 5ãnwÂ&ÖúlÆa9ÕIïvD\ BÒĦrzŠ‘†÷ÆÀ|Ã5¿ ‚zÜ ¬ŒªŸUû%Bê0_XÒm–FØû1Ý~Æg«Ž ‚  ±­ÊÓ˜î\räîÝhqµvíÚëé^“ ‚ äpÚ¶m[Œç—K“Èåݸ܂mÚ´Éî}A¯åÇÄ¿ü—ÅîL"+ÁâÊ/½+AASD•ÐøÏvoÜT‰,XÞ,AAÈòÅÿÇPS<ªBšÂpd°gï%©.å‚ ‚ ¤ŒIjŽ1šæ¶V,XÞ¬4›ØÊëã#§QAÐÂ*Ýâ ˆÀò~ÒtáDOw'6’!æúR*Vxs›™)t°.NÇ–û¤åZ‚ ì=Ý^"X9 Sdpãk Ƨm»Û»~Fï{jŽÏéZ˜Ç$‚ $K†½Š+‡Àlÿþýµ¨:t¨Ëʱ|ùrªU«­^½š:tè §±øéÙ³§7[zlX a9¶D¡žS}l÷Ã?¤!C†ÐÔ©S©}ûö®éXž—5qZ‡9/)Ë“i)»zõ*EFFº¦£>D%o×i}IÅl%'\²Ârd :ûZpɪýAD`å(ÐwéÒ…^}õUºÿþû] òš5khüøñ4jÔ( ×0,=°l½øâ‹Z°è²¯"Ëa>,b,ZLׄαcÇ诿þ¢Í›7Sƒ èðáÃT²dI=—3—aœ¶ËÓYÌ9Õ3Ž%,,,Ň-[¦kÍ^—-¤xºéâtšïÎ¥jÖsr×ÚÛNJèa:[þìkc³¯ƒˆ,A„ÌG\„94À 6¤ýû÷k‘KÄ þ·jÕJÏ?~ü¸!—.]¢Ý»wSíÚµuc}æÌêÕ«Q÷îÝéôéÓ®†ìܹ“š7o®ÜÉ“']®FÛM…2cÆ êׯŸnðï¸ãúì³Ïô6Q°\`` ¶p(P@g¨?qâ„k[¹sç¦)S¦$˜gºøx[öqó43‹…‹Æüùóëu㘱¾_~ù…7n¬·Y¦Lš9s¦k?y?Š-ªËüùóé»ï¾£²eËRpp0-X°ÀµÏ8w;wÖ‚ççÔ©Sz5jÔ è:þù§ž¿aÃ=oÏž=T½zu=Ljå±M,ÏçûˆeÞ{ï=×u¼8‡/¼ð‚Ë¢%îBA„¬CV¤cÇŽô믿êFÖ+¸Ñ8£ñÆt4È?ÿü³]h”1ïµ×^£·ÞzK‹ˆ£±cǺr0mÚ4Z¶l=ûì³ÚfÆU™1[XÖÝwß­ç÷íÛ—fÏž­-g¦`ƒ…ëÈ‘#4hÐ ú¿ÿû¿ÛršÇÛK*V @ •+WN !»^±bÅ´«û1lØ07n]¸pþûßÿêc‹ˆˆÐlß¾] ¡O?ý”Þxã ½_[·nÕBìÞ{ïÕû…º¯¼ò Mš4I¯.ÚÑ£GëyíÚµÓÛÂgüGLþc\ÌÇgÔ‡Åòp«¾ôÒK ÎŽiÕªU®ïØwìΖµ¯ƒ ‚ùˆÀÊA°» (X[Ðàbì¥[o½U7À°Ájƒéßÿ½k:Ê·ß~«ÝxhðÛ¶m«tXÁ ŒÀã?®ëÕ¯_Ÿ.\¨ë±ð1÷•+WR¥J•¨B… ZÀ2T±bE-ìL…õa·Ýv-Y²Do …ça»<ŸQ×]°º ¬G°ÁrÂp=ăÁR„õáÜ4mÚToçñ[¡¡¡º€gžyF#¬‚;vì »îºKÇùÁ~ð>ÃÕZ¢D ýççîÚµkz[|øá-èðëG\æóò¿øÜ²eK}ípÌ|>Z·n­]«|-¾þúk½üsÏ=çbÉA!c‘¬iÄ[Aø¬_¿ž&L˜ _¸¬ð",Ä_¡a†(;{ö,•.]:ÁzX ¸ìÐc/^ÔëòhøÍ¸-µC¸ÀRd’7o^jÖ¬™ë;¬2X\`Ø6Úó<Ž1ÂÚL‘hî§SÖxsž¹]Ψo‹K§»A„ŒGVÃÂÅ´~˜ ¯ÝÛÌlŒY`9Å7±Õ˜–,{\?§Þ´¤!¡¦™zÁŒ{:þ¼Ë½h»M+“µÆŸ¦ÅþÎçĶˆØ.§é¶@³ç»›æd9³-Nuí}`«»uÍc1KRÛOj^v -³SÆÕ«WõËŹsç´°jÙ²% 0@_G§ë—ÑËÃZÙ¢Æé{f'ñcÞWö½•’øKwÇcž[BF!KðH츈#X"† BS§NÕ"V*~Т-^¼8•*UŠn¾ùf:v옫Qˆ«Â÷úõëÓúõëµX (Íuøáu•-[–Ê•+GÕªUÓëâÆ¸‹]òT¸Á€Å – S¼ÀE ¡i6Ö_ý5U©RE[ýÿÆÂäĉZœÁZÒ¥Kýçó05ÜŽˆkРîˆÀV1XÍå` 4Ý·“&MÒYçÍ›W¯Ç¼ÿ?ÿü³^7–˜ž9s¦ëc·ß~»ÞÜ'¿üò‹žçäÖÅg¾žÿüó>'°üÀµ ë$o?5û–]×”¯Ž ÷4^`¥¹ï¾û´Å/(l‘4­Y¶`v'<íé<Ï:©ß¶@²…®“ð<–¨)”݉b'±Rq-"KÈD`  Ä ¬IxšÙÚ!ðÖÎO¸EŽ9¢‰FÙ·o_QÄk4šp5šƒž‰sdÖÁº°Ž={öèx-ü篽ožŽøŒs’` m{¸ €cÞ¸q£îX0xð`—ˆ ½ãŽ;èâÅ‹Z袃[¹î¾ûn-F`E3fŒî„Àó^yåúßÿþ§—ëß¿?5*Å "Û›5kÝ{ï½ Ü¯fC‹Þ¤¯½ö]¹rE»ƒŸ}öY×z°ÎAƒiqŒÏÆ Óë€E‡·an“…!öDŽީ|L¦0Onß²Û‚eŽÊ×BkÆŒúüðqâžfQ‹z|ßc>„cPP™ 6t‰cÌCL#ßû«ï¼óŽþíA¤.\¸Ðu!p݉è¤Ä7ÄýôÓ1W<n33O”7X°˜öíÛë†ïþûïwMCÜ>ˆ_bœ,sì:…Õb“¿s—¬Šh4ÑøÁª€˜)œ'ÔCzó|ògþn»ÛœzˆõêÕKwR€E"¸yóæ®ûÛàuš kyY;§7Ô|Lì23ÉÞ¤ö-«1]¿æñ ,ºì"äãæsÅßYœBˆ=òÈ#Zã÷1þ|-ÆÍüpü»b1ÌCXñ¹‚À…À2Áº±-ôR…uÈ\?^^°œ=ïË/¿Ô®{,Ç)5ÌëÈiY „qb_La̹êp°}¤sácçóà õx}üÂ$½ …ŒD,X‚Çân¸s>Šx0saKµƒïüÙ.ˆÍÀ|þυ盟ÖáM ûˆ¸$ˆ©•+WêgÛ¶mÚò÷ôÓO'ÈhoYØJ‡F{ùòåºáÁÛ>R\0°üøãú¼ QCãÅ11°&$ç¾µÌv–ˆ+X0x_°~à°o°°ð±X/œøÆ1-[¶Lþé§Ÿ\Ç”TVsy§ºYu=Møzñ½Éq‰ÌÂÛƒ»ÇÈqVæ±3nÓîlÇ%ÞH:ŠìC–jœ~°éÉ‘”’|C,¤Ì|?\X™Óœ‹Âóy9Sˆ¡˜uø;¯‹×aS`±ÛÑè9#»¥gÔËŠ+êTï¾û®î…w×]wiëzÏ™V36 ðÛ=Ä‚’±4˜ˆ{áu¿ýöÛÚ}‡wr~ø¡k9XR0¬‘;÷-o 瓯µS}ôEÌ\p›uŸzê)„ ~Äà ®‡÷ LJޒfœ/gÜÎ|Ìzö¹°Ç Ì.ìq0Q`Eüä“O´åi8·pªƒkXX@TB”¢Dı-°ì êö±›"q‹,¢±,âå ¾±~ß|¿aÛˆ—3…yR½ùx{,ö c®‹y°„ÁR?ßß\E9ÀþÁµy#‘Üó(£Å–¸ÄÜ=g‚–-Rõ€º”»GOfÿ˜’oŒí²äæ©=„¯×l0Ì:æqšÛ2]„öÀÖÕØÚô¬›ÏÇD¡‘uÊÝenõXð,ƒïl±°ÏÏ3ã“xlEaw•y>y–°åõbyĦ; ûÁðf02Ä/‹'{˜#Þ&»“ø^áa‘Ìc2ï Ϩgï¶ÇbÝiX¥Ì†÷ûÆ1s D\¾/¼ð‚ž‡ý…ˆAìöVªçž{N[œ°Ž;wêºëÇqŒØ$z >|XŸ;Œ¨€Ï|>Æñt¸—/_¦#Fè$¾ÒXgǹåÛ3× #Öï´m¸²ñ½ ±¾þè틬‘p >öØcZ¢>~áÂ…õ±Âå‹§ˆGC°?‚öÑÇ¡éœpö™gžÑ]ì3zº6nÜØõ"‡ÿNbß°Ÿ›< ¸ÞÝz˜äêð6=åå#-@h«{s€úx^•“ª\PåŠ*B„ 4&5ëó®£L²T`Ù´-f–ØJ*{´ÓÃÁppXö4§õ˜uìºÙ›ÐÉýizÖ½™œ“E–=Ä)‹†ãn¸a·÷Ùœg&³õ„E”yÎÍcãÔ¼NÔáFμØ3š÷ 1 '³ã)¾9×DZ7üÙl€ø˜x¿í}㆟á¬v)ñ55E3¥;ÕåsÀ"“ácãã´]Å||œÌœN÷Çj™÷°yŽÍ{óø¼:Ý3l1æûï_\ÎênƘñ±b{˜‡s±±øÛo¿éå!Úy>>³`æû­©Zâ9#î >&8Xi{ôè‘àÙâôüÂòè8xTS4¹{Öb=ÓjZ‰Só»°ÙAF , r’…æfƒ+d>è)ÉîLÓ}–Ú)4X°påTpãb>@ÍaFÌåx¿LîdA´ß¤MÑÈœm³-Q ^s;¦3ëšx^c6æ¾Ù–Ãäö-;ãulk„m•5…:›mi0ï [hšV³‹-ó›ë7§›±|æ}ÇëäÏf~6¾ÿL·.Ÿ{Þ¶°onV7¸‹‘T±eÈ{gî o“Åýåí1Xv†î5Šž–ˆqC˜\ºüû6_¬LЫóøñã®ß‰Sió…—_Úø·bv²÷Ïi=Œý;NI<¤§"-¦,æöô?ÿd÷î䊗,©Ý.xËv2í§S<ñwÛ•j»ýÌúæCÓ¶ì9¹]íF–çÙËÙSsû¦¨öþ˜ë³ëšë´ÁÜWs{öƒßv›Ë™oþÙ-šMlÁ` Û5ÌbÑ<¦ããd‘i¿Óyµ;.˜ ¬“øæõØÖpBf, m-vrá?:r ãÜ—pN˜0ÁuŒü²‚幣йÝä,;žŽS†Xü0 nY¸`‘# ‰C¶•Ž×ÁCL™>û7jn‹{›²(w'ÄTRá æ|»#Œ§_ r’Ät/ Y âMÐ 1'fÌQZ\±fCË—S1ç™IHÍyf¯J§upL³G§=ßi»¶›†è¦ûÒÜ^¿»íØÇ“Ô~ØÌN NçÂŽ½Ëìëi÷„Mê»Ù1ÄižÝÄî]ëÔsשg®y^¶ïnžÝ‰Ä“v/a»Ç/hߺu«NÅ‚`¤à–fG{ÿÌûÁ[c¯[Dó9D‡s¨£ 6èt'ˆÕÃð`°üáYƒø7€ h詉ühM›6Õç®L™2®ºl!CÖÅCNq/U¤kÑâŠGDp—É?©!¶ì0OF,XBŠ•õ`HÀ=Íx”´`Zdì¶ÙÝ)^ÍÉ\ï„Ssy'¿“%Ë]½¤öÃÞ‹s§—ݯ»·ù¤,ž¦åÏé8R¿èîÞàÏîb$Ó2ÏîXℹ¬i%3-s|ìfl•íöµÏ©·Y¯œÎ‡í6â‰X_ýu݃‰W‘H©P 9!° €üq=8<ê"×: .[°àzDÊä¼Ã:Ñ[íz*ch2,‡|†X"`4tP@¶t@&ˆcì'±…ÎȆΨkºy=Ý](KHéz›}ÀrÅÉÍàà¤óSBJ§`~§é6NBŒãfðÖÊñf£‡%öîŽËl œê˜¹NÇ™‘< [¤dßS*°RÒùƒë9 tó{R±4Éí—ýß¼ìe9Æ‹ëp¬ž;æäîJj»7N÷ž)5˜ÎÙì³…üb,šÐq‚Ÿ=¨‹õÀšÅuy>€pÂï¸^½z:Ö " õaÁØÒið6: 7¬Œ<$æáAðÁ½Ë£ Õ ÖÁ=ùy²¥Q–,"°²§a;¼á:ØoÏüMûl9`Ë ŽÑ)¶ËÕÄ^?ÀÙr³;>*«IÊ“å„Ù©ÀÌæzLÁlNO©e‘3ݤºý;}¶·ivÈ0{­zc|Uzp×é.гðï¿ÿ¦?þøCO·“ó9E¸êîÚµËU×F Icù;gÖÇùÇrpÕÚËa½°PÁ2†¸0{bË„—c ¤§?%KHž~#߈Øãêyú50ƒ^Íd‘æ%<‹GŽÓ°ÓGØÅ\§½~,ùæ:0³æuB’_XPwîܹ®ºœ!BŠÓ¡ ›>_¯º]¹Í“µyóæD£ Ÿò®aŒM.ö½æéÏFX‚à¡xÃÄÜWÄmtêÔÉ”Êã=rn$$•t ‚åd˜<´ º#æõ8°•ƒ^‘@õyPbLçD›ÈegçùROff3^J³¹^'Ñe6¶¶È2;'xcN«Œ¼–È|d³ˆ•âßÓ{öìéJiø\våq]üþ0’‚Y—ï%|Æø¦ø óv±²æ#ˆÝ^¿qdâÇ3ÃEÀiˆ-Äm™€{C»,AðP<ýáaî' †™ÁCÁùVÅwN‚ 0P6‚`1tâ3¸aüPç@Ö .èáVFåê©„ W¸Ο?¯ëaH,ÏãÍÁ­d‹+o§žˆ§fÎÚ¿páBí‚B‡4ðÜÛŒ‡ãq—ÓÍi´…œD‘"Etï@ -ëÐG}äVç}ã·Ú²eËÃOAŒâšã\³0ýàƒtl®9×5]ýÈ‚e`¥Bæ~>ߨ¶Ý¢E‹DC\!øý­·Þ¢ªU«&;Äž ÜÙÇ[³çî™Y’ɳ%ãA‡±Â$VÖ€§hјÂŃ^c°" ±Äy‡ CÐ@D£×Ø¢E‹tC‰s{–[F#ùä“ORùòåu| Ò ¡Ä5ÄÐ:膂u£1ÅØ€Ø6„Á?êYÃ# @$ W÷6òèmÆn@³W '7¸YqíÌ ÿ(OªS»uM×þóo‡;©ØuMK%Å#˜‰IÍ,ÿ¶{Ï̦o¾™‰mÍlý<"ÜζŸdt&wyê‚f̘¶BØð4èʸøÁŒyÜþ ‚›!˜ðæŠd‘lÃ<Žñp7–"ð–$„ž 7°M°0áÜã™À9'@p2êÁ½„î÷œÔ >£'¬hä‘èrÕªUú3ÏÃz¹¬RXŽ×ÏŸQÐÛ ƒHcÀjˆp1,g›dZ±r:vÇÛšËyÁÜ;O™SN9»žSî»ärå9å sÚ;G·tT^„‚ ¤ ~pC@qÌ[|7“ÔÂí‡7O‚5³@³{ ËÀÒ…F“œük 4~»µ3½ßˆ]ì³'ÁÌcÿ±`æë‰ëñÃó8n؂ل¯- f{ mÆœöî»ïj÷6ûòË/©F.« wÝOo o'¹ ÿf3Ã?êÚø7fŽ\à®®™ñßi,B^ÎüÍó6Ì}sJ¿`»Í俞n™öì½Ák@°,,ÖÄz˜Ì˜1C?,a}0ƒ` 1;°qXkƒ@YÄé`™xS¾^–Tä×1Ì9¹¡M¶`ÆurÌf¯1KÀ̇¢½{÷Ò¾}ût1çq@³SN-Ó‰ðôrƒø3fŒŽ²Ü…8œ2üÛÖ ÛòÄ™ûÙ½nºØ9Û¿¹Ž¤ê:eò·çÙ#أأ ØYþ“Ëeæ)ˆÀ!C7nÍ›7O»÷Ð[A退Mš4ÑCup¬9yæ™gèÕW_¥êÕ«Ó”)StÜ ? ± å+T¨@cÇŽ¥I“&¹° FÌ—=†œ'?|=ìÌwË"êà>0{›9õ$ÌébËËIP9¹åÜ cd;•”kÑ^ÆKÑÞ†ÓI¦KÐvUzC€;¡ é‚èp!®.%³ÑÃ<ÄRáóºuë Þk®L7swo;s7‚§!ÜL73kÖ,ýËyÃ×€`¾ÿþûµkƒ&CÐ[0C #a¤9`F ;ÓS‡^bl€`Æ Ì]˜Ç‚°`>pà€¾ž˜7räHÝÉ,Öãéî¡ì$½þûÚË;eýOiBX§z)EÀݲžŠ,AÒŒ™qÝŒý`Äñë¸aDXFÌf–w³‘0çÙÁÌfWq³{¾7<€=O̰var(!ÀÝìàÀñ8r­In Gsž»!®ø¿#•œ•ÐAîQRbËé»7"K„táTk³òÃÖ þŒÀåÿüç?ÚÕÄËr!`ÆXسI ,‰%ÓŽ§ fî²o6þö8–vž+¹Þ IjLI§ û¶»±ø´)Èkf—ØÚà¯E9ß3ˆÍ²êF°¯ÛtýD` ‚.Ì£ÙóÈé-—SüG.£§žz*A{§áLìâ$°ìý±c±„”ãI‚Ùì-j×ÃpŒ‘ˆé”a‹*>§H¾§OŸ¡#GŽÒ¡CGiûötíZ$íß¿W<®ê]£"EJ©sž;Áz/]:«ççS×–ËÂT¶lyÊ—/H»zCB*PéÒ%tÊäóãëå.ì"¶D` ‚nÌ.ߌÝhš )7”láØ)3ˆ5©`õäâ5¤±M;ž$˜í´ ¶Ð³pœ±ÇzDdÒß±ãoZ½z ýþû&õý,]¸pŽòä V"¨0U©R*Wn¢J;½ŽŠR©R!Z`åÊ•X`]¸pŠŽÝ£¶Á½LO©õÿJk×"gÙUBŽÎâÅKPÅŠ©I“FÔ°a=õ9„òçÏŸÈêÌ×ÓÛsÚ‰À!Cà‡`R£ÜÛ¤Q׌ï1d^§ý6›šø!mØ‚Ù)©kV f³ž]W܃î±êFvü~XK_}µ¶mÛFaaáT¦LªU« Ø‚¨`Áb”7o~%´ò¦x;AAù´øªQ£i‚éÑÑ×)""L °k×®hÑõóÏ iúô9º‡p©R¥©M›VÔ£GWªV­šZOP‚{ÆÉÅìMˆÀ!ÃHNÜØ³¦Ë˜o®7rð«·àd™têù•™‚Ù Ó²%ÂÊs nô¾œ3çsZºô;ºr%”Z´èI÷Ý7€*V¬E%K†(1”)ûàç—K‹/¦aÃÛÔ>\ ýûÿ¢ƒ·ÓO?}­S·Ô¯ß˜î¸£'µk×F Æ©ìxJoºÖ"°AÈ2œ†ï0˜%{ö“ÒžbÀ¾žY!˜mq%$Ä´Z¡·ç»ïN¡yó¾ üù‹R›6÷Póæ=¨B…Ùzîòå+Duë¶Õ¥cÇA´eË´fÍ<3æUš5k6 rŸšÞA[´ÌœXÞÖCX– Ù‚X¨<»™ÓgÛŠà”žÉ Á,÷‡{øš!½Å'ŸÌ¦·ß~—0‚QŸ>OÓm·Ý£ã¨< ¸#[´èEM›v££GwÓwßM§×^{ƒ–-[A#F<¡c¶8[¼íröt$S›iüµu+õèÕ‹J—-Kå*TП1-)Š—,™¦m 80CöÙ\OZ÷EH9"®²Ó}Ä2 †ÀAwüíÛ·ÓŸþ©ÿ#s:Æ4`æŒì(f×~»§ ëšùðùGûäÉSiÒ¤¨GÇé7–Qß¾Oy¤¸2;ñ¦›jÒ£þ—Æ[ Ž#/½øâhÚ½{NžŽ86îDá ûÅ‚%d=ü0xúiúfÁý£X¼d yàÚüûï¾-dŠÎèõœþçŸ,;W9 w= ¾»³”iÃîMÑtâÄ Úµoí;¶¶nÙª´Ýêd;{ŽóÒÕóW©h±¢z î*ÕªPšu¨J…*T±\EÝíÓÍÞ|vÌ•5ðX<ƒÞzk"=ùädjÚ´kvïVªÁ=¡5lØ;4uê 4jÔ«4vì‹T©R¥xº»P,XB¦qúôiª{Ë-úÁ ónß;îp‰«“'OR—nÝ´•¨c§N´oÿþ˺›˜‚¾wÞ©§·hÙ’6nÜè²49Yœ0¿}‡z^µ5hîgŸ¥x=üÛæ}ÁÞ|kâDª[¯ž¶Òa¬5!1f£nZLØúÂÖ.æ›AkV¯¡ÜrSÁu¨iÛ¦”§`Ê[þR)„š5jF ë4¤ò!z\;>vÛåéÚìÀ¼¸ÿG¿>š~øá*R­Õº·UêT‰ò—ÉŸîmœÙy†ö,ÙCÛçl§ØÐXêÛ§/=:äQ*Z´¨þm˜ÁÉÞØÕÞÓ1{ Þv[ºë®1Ô¾}ÿìÞ­ #**’ÆŽí§~ÿ¹è…žÕÏD´Ex ÈÐçá?þHmÛ¶ >žWå¤*T¹¢J¸*× ÙRSX°„LWX­P2„n®^] ,4¼ûöìÑY|Hn~Jé¯Ý}÷ÝG-Z´ ÒJ¨4nÚ4]ëƒØ´OHìܹs'­ùe ýøë´gß (@%(°| Õ{ žË*T,ˆrÇÃkg¯ië8¿ÿ<Zsˆþ¹fÌŸA>á>T½Zujߢ=µoݞʔ)£¬v¯"iÀã0‡@ùbñ4þÍñM]§v¥ ­+P@þ€ ÙÎsñšÅu©{]Ú½h7}ùß/iã¶ôÜcÏQãzuŒBüVÄš•9àzŸ:uŠ®^½FÕª5ÌîÝÉP0,OÍšÍhÁ‚wéàÁƒú~â{ VRÜçžú›÷Ì×`ᆠA£F:Á RHHˆþ —áä)Sôçyóçë8+wó!”à¦C#×!⧘˗/'Ú‡]êͽaƒT«fMz{Ò$×ôÔ¬û‚º°^}ôñÇú»‡Û³eÛöÂ0êÔ«½÷é{t©Â%jöf3êöE7ê6£µßžBÚ‡P‰:%tÉW*ä Ð¥PH!×ô꽫S—÷ºP÷O»Sï…½©ÁètºÐiúïÇÿ¥>÷ô¡·?~[?l“k'Çý˜‰.s"l9Dðúð†Óˆ§FP±ÖŨ߂~Tµ{Õ W6Á%ƒ©Áà 莯BaôÈcд9Óô,|pÈ5ÊXøånX{¶lù1»w)CÁ1mßþ«îeˆß¹ý{÷ä{H,XB¦1cút?amÚ¼Y‹LÆ×qOp…U©\™>ùä“˺›?ñÍ7u<Ö‹é“Þ~[Ooݺµb·c Æ«ã®`éxbøp×ôÔ¬û2lØ0]·kï½ûnvŸZÀWÛvn£É³&Ó·‹¿%ÿBþTÿéúTû®ÚºÑM/XÊåã—iÇü4sæLúüóϵ˹O§>T®l9‰û¡‡¬Ù¿? yl>{˜:¿ß™ªÝ^ürgMLN‰Ú%¨Ç´´iÊ&šüÁd:tà=3üíâžñuò–8o¿Å‚ *‘U€V¬ø”Ú´é«óKÝìܹžöíÛ¢“Ž"]^t¹#ŒÄÓð¼=RŠWÄ` iÓc°Lwà™³gèý™ïkÁT&ˆê=R*u¬D…3uXhm¹•òåÎG>ø(umßU72fÜ6àF†-WpÉ~l0]P§t¦"U‹dÙ>D†FRlt¬‚¿qNþq’6¼¾Z¶lI/>þ¢ŽË‚{ÇYNãzbcé©ð3¹ËÚ¶í@.\V/#©wïǼ>ÐãN˜0Xß#ÇŽí¤»îêC­ZµÒaðl4Ÿ‰¨“^$K„lÃì øËo¿Ð‹¯½HGO¥6oµ¡v!™æ~²Apv³§›i+ÙÎù;éÕñ¯ÒÒåKiøéAýzÿL‹¸‘n¾&ûöï£û»_µç©ûÔîT¨b¡LÛfÄ•ºrü Û{Ž.¾D'ÿL»W¯]M;÷î¤>ÝúPÊ5¨r…Ê:ŽÊæÀ¾N½E…”7Ò3ÌŸÿ¶ºïý©G‡¼Vd8q€¦N}‰Â®ң¾EãÇß­Ädl‚”-žîf%BŠ`«ÌóÏù˜^ÿ:kXŒú¼Û'K­$&p6ÞˆŠ×)Nk^XCÞFãF£¶-ÛRpp°~»åA‡ù ÷Fk´ùº wæaC´å*³Ä¶uaÿÚ½d·¶ ^ýç*ŪF/_é|T¬F1ªÿ`}*Y¯$ùúëŽ ˜y5’ÿt˜Nl4mÚËtôèêÞ}(ÝtSìÞ­ƒ˜«õë—h‘X±b>üêwœ—ØáÆÂÊWžè&%B²p#ŽÌßãÞGsæÎ¡š÷Ö¤V/µÒŠìDg~n{õþ¬7­~q5xv|f$õëÝO÷BÅ~£Ç¸ÑD[ø;úÍÑt"ôÝþÙí.®¢#£éèú£´uöVÚ¿j?å)‡ê®«Ï{zrhùÏÉ¡•Áøøøê î ¡3ÆÐ+¯ÜN½z=JíÚÝIE‹–ÉîÝs „â­-šB»woRÂð!½ßÈ…W!cæÕã,Áëñ=}šüú‰ü7oÖߣZ·¦È6m(60sã€r ¦¸zê•§hÕšUÔáíTýŽêäëç9±M®þýýßiÒû“(26’ô cMn$‘Å×fÞ·óhù²åÔmZ· Wçöœ£µãÖÒÁ5©XµbÔvLÛ4åÐÂù†ÛÝÈeš”¡[¸EçÐZ8g!-X°@rhe Õ«7¡Ñ£?§o¿J_~9I¢ŒŸ›7ïA*Ôð˜óz™¶lùV¯þœþøc5U©Ò€^zi6Õ¨Ñ4Ñ>ºWž*²D` ^ÿo¿QÞW_Wñ?²ÀÙ³)¢K =š¢Ë–Íî]L7Ùùð°ÅÕÊ5+©Ë”.:Õ¨9…¤ãËPDÅ_%¬iÍŸkNèýÿ¼¯§õïÙ?Ñ9¼D_›£'ŽÒÄ&RƒÇPÅ3lý°ZýýÍß´îõuääO=§öÌöZ7ÂuËJòå+¤Þ›5ëF+WΡU«æÐâÅQýú·R½z픘©K%K†Pž¡\ªñðWÅ/¾À”Í dk¬:Ï{vÑÄ\êÍsçò}|™Ûú>1 …®ÿµ(*ÿó*·þ˜[—*¤üÇ.“_d4Ÿ¼B‘Á¹)¼`:§ð+¥óÑ?uKÒéZÅéRù™½;Ôöµ¶´hà"š½p6=1ø Ç ioj¤Y\;޾Yø ÕVSgz1Åâ­23‡Vràz ž ‰R—=ºL3‹,†{ŠÈJ?¦àªT©N‚yáá¡©¶š#WRb,§ KÈ,å +ÔéÓ”kçNýÖ(ˆ(%®C‹•;"o½•BGޤÜë×Sàܹº¾1%KÒ•?¦ëUªd÷ѧš.•+Ó´aÃtš¢EŠP¾à`Ê”`ÀÜÌ€]ƒÈ ýÁ¬÷i^ø1ê9«®\Øí2%¶ž¢¾w}M—Â]Ó¢TƒoZ°®” &ÄÏ(Uxÿ*ú÷YÊwâ ÙsNÿ¯ºt/ž£ËeòÑá67ÑáÖtÉ#\g-F· e.£&·4¡–MZ&$ÚÛz§ñ5ZýójÝùçéåâá‹Ù*®Ì ð®‡K¹µÊ5/§ãþ–?ºœücýiÄã#œÎqæm×ЛȈX¬œŠ,!ÓpÊ;q"ùoØàQ>áª1¾~=Õ늮T‰B_yE°#z " =ªá :”¢êÖÍր봂¬/‘êP"T Poëþp‹d²ÀbÌ߇öÓGs?£V¯µ¢àz¥(ÒMýà®RÛ±kµkçùrÙüÉÆ`/¤çÙë)¶ó U^¾Êÿt˜jÎÛNT#¿é‘†´¯K•t -äaªqO š6wU«”0×’=ÜÓáŽó¿šOÚV B•Ò'† hБÓ÷³¾™.®Rš¹µ`™CÓ*½«Ðò/–S±Åèž¾÷èq Ù’g¾‹Ð< XB¦›??‚%(×¶mé[UWÿïÿèzõêqßu*LG@;b®@L©Röàƒvß}^)®n0  PäËc·e<®Ùì¯gS¾ ù¨j÷ªIÖ¯?u³viY>]½¯– Öå`ûòW }ÁC©þô?©Ã‹«©á‡›hããiO›):ÁÖ8_uÕ¡ùóçÓo[~£Ž:zeŽ%¶Úœ9s†6mÚDÍÆ5K÷>#+ûÞïöRÏi™g¹JOø“›OÒ‘ŸPDdM›1Öþ´–Ý5ˆZ4n¡ùFð4ÿ>$¼àIˆÀ2õ»öÈ#‹Ä+WR®ýûSo½RO¸#Û¶M0y®Š½ýÔBîú-·ÐõªU½Z\Å6—À2KfY°¸Ûÿ®=»è»o¿£Öã['›óèP»:Òª‚vfTA¾Ÿ©YœVü·#ýñ@=ª?íêüÔrºéÇÃôÓK­´K HŒYkP-šÿÍ|jP«+¿Ñ‚sê‰Ãm˜°ÀÚwxŸÎÞ^¼Vñt­BfÃÿ6PãÇgh-&32ÀïøbýgâtøÎ;Sÿý©ºzéÂõä—É/x"°„,V¥Ð—_Ön;ä­ X²„üׯ \O.¯‰z@† Háwß­]‰PT¤bðÖt îÛÇÕH Á`—»µ23¦eÆ3´õªJ—äc×`¹ÊÄ …ÖʉéÀm•èÖ—VSñm§èû èx“´%­qg ÚþévÚ´mu(ØAUˆ†™eO°z˜y~œöVÆûwPîü¹)ÙÔeS··³á ”;_î Í¡ÅdføzCëé ð‹æ,Òþ7jøäîÁ³%d)1Å‹SD×®ѱ£púßÿ(`Å d¤s»Ld«Vtí™gräÐ7x¨r06„Ëù›2¶^íÙ³‡–-YF-Ƿ̰ŒÝéÞ7Õðk×cåÂÔnÔê=h!-ü´wšD÷Š+Ò‚oh+F¶pn³ËŠe \»QåbÆíþ{7©RD[„ÒÊ™gh÷âÝÔmr· Ë¡$|úHɽà-Ç’ÓñœÄ„œCTùÿþ;å?žV­JR\é öqã´0Ëi˜T3¶„-ZULWÊÒï—’!ªÔ±Rv~"Òañ´ž:¥ÃmÏO…\HÓzª÷«NGŽ¡cÇi7[DD„º%£´À´·¤ Ho]WòØ#Gˆ¦M£˜½{éºÚìbáø?öÅÜwìÚAEj!ß\i„ĨŒÊ¡àr\ùìJZúøRº©õM4`ÁÇ—Yb3ÀßñõV(Lg€Ÿ6gšŽQ Õ×—Ï!Ÿ¿äÈŠëžTIͽàMYÍs""°„¬]ªwï¦|/½D ¢Ü?ü@1E‹ÒõÚµ«SèóÏ»‚Ús"¦ÈÊÌð_ûËZªpk… µhd$È‘µz|Ê~n}ñ{o+µ­V”òß”ŸöÞCááá –Ùp±Ât.,ˆLkO3르®ës®\D_|A¹:v$ßÇ£èï¿§p%°oTfãzíÚ5úçè?TR Í´v!Œv~µ“jßU;CrhäÑZpï:¼î°ÎßqbÇL^Ç„3À×¢>Mþh2Mx{>}ZŸ+\cûúº#«®»S]¶"Ç`h¯dî^^D–g#.B!K@Ϋ<óæQàŒ: ;²«GôéC×Ô$`Á‚Ä= ýüèÚ“ORD·nÙ½ë9î™vðàAj÷L»ìÞ$AúÄaÝ~ßBªŠ^iýk¥jyŠJ]+Ñ_¿ÿEZvp ,í&yò$[W7¬è½©~êå#÷Ì™ä¯~+‘uëRD¯^:ï›OHåR /Ä0®DCz²¬C…] ËZúšÜàc¥Øsçt’ݬ¸îv]Ú·bY|Ýq¼ø¢ã½à[±¢NÙ‚{Õµï"²<X9”D?öLòëû„…鞃S§Æ¨ Q͛ӵáÃ)²eK Žy6áýúélíŽAíB†ÂoÁÛwo'Ÿ@*^Ûóݱ‡ÚT ]wÔÐ)Ò’' ù£Ö}½Ž._¾¬“¹šn$š;—|—-Ó ­Wp0ENœר>L¹FŽ$ %¾C4r©¨‹O¹âÿǢ᧸á¡~ý•~û"5¢«£GSdãÆÚ¥‹}ö ðM³u(æz 혷ƒBÚ†¤;‡ð† ðÅ'‘¥¯ÇìÙäóÝwú{V\w³nì¡CäÿÜsº®/,^”ô½Û´©WŽBÓ•Áü믿¦Þ½{ë… Ü3-C~°ÈM³q#NŸÄ³vÕªtmèPЏýv×ø€ÈØŽaqL¢š5£kÏ>«]„BæÃ.Œõ›ÖSJ(°°gº îQ¤pØãoª¼loª­XQ1QtæÜÝøšn—¨aÃèúC¹,K¦õÁGÝ“ª)¶BŠV 2ˆ¶ÜAq»ç“¢º¦ëÈwË*ôÄzX¨˜  ºvË-t±sg oÑ‚|oº‰##µÕõ£"” O}¢^z&”ŽmO¾BÜ@ª†Ï7c7Èø%Q׌ŸÑËž9C…ß_[-ÎÝsn׎®¨†”òæÕ½áU}ì~› ¤<¹óPè©P*’zAƒìé×î§;‡VVg€O-Y>èDKXJ•ªV¢;{Üéº6|›I{cÕyŽQߣÕyæ{!£¯{RuÕÃ8®ÎåË”÷Ýw)Ví î…3íÛÓeõ\ä{!ÈŠáJ`…< X9óaž/_>¢ÄNË–-©cÇŽ4sæL×[wgN‹ÈBœUÀÂ…:ÎÊïðaVqzÈš bØßx¥ƒÚ_z‰¢ê×ÏîÓ•£ÀuG0ð±£Ç¨†*^ƒºŸ¶»‰ÚYKAgBéj©|)^4Wž\:××¾û¨}Ëö z3w~ E£×%¦ã³Ý«Ëîýi×eK”K`©ß \âWUCz¹P!ŠˆŒÔ ¯Sþ³`õ;ñÏå¯Ó, gjA~*ôêKO-àÓKÈ­!Tÿ±ú4uÚTª}smªY­f¢ž³¦åÞLç×=©º@߃Jà‡«çóU%°/)1‘è^°ÇÑôô¹9X9»K8z¢ìß¿_?¨ûöí«ƒ|í‡IjÞ†ÅY©=â¬`±ŠèÔIÇY% .;P50ÔžõàZ_¹r…BÃC]´½¤l@Âb»Î¦J`¿`?ºxü¢WvÏ,`6^N"Ãßê%W—Ýè¢E)ªsgòU¿Í<ááä§QÈ1CœÓ‰Vù*åõ~õÔ_j9³ëLºshevøŒç»þÐútøÇÃ4gÑz®Äs‰FD°Ý†|½L×[F_w»nwe‘"Ùµ«¯÷‚o¼èÃþš÷‚ ríùˆÀºÁÁÇäÉ“iÞ¼yT @zçwè“O>¡/¿ü’FEM›6Õ­ùcM6[¸›8«°{î¡ðþýõÉ]®œ¶r¡çz JP{ÖÂü³gÏRøÕp*X¡`vïRª¸\®…ÊC_Lõ²%ê” Ý?ïÖ=òl—Ù@:%{4±ΔÖ5‹LözüPRfrY³×Xuhẅ: Ö¸”‚÷Ó;Në$iÍ¡•Ùà3¤¹u­´äî%´~ãzºµí­ ,A¦åÊ´feÖuOª®é9àý³™ïs\ÒÌô]ÈD`Ý ˜ïAƒéæ¤I“è§Ÿ~Òo?]=zô iÓ¦i±õÀè::Å—ÍpBX¥(Î*)ÔC$ô©§â‚B%¨]H%±>èm•¶·÷\¹´5×ÎKÄîw–§iî~+ÉÕåÏØ. ,4žÑñÉwͤ²f¬MH…K…|VùRa¹‹ ‹¢KG.Q»ë¤ùœgVøÌy²jß_›>_ð9Õ­]×q8ÓrœÄMZ¯»»ºf‡÷‚é®¶‹{Ðsuƒa>°ñùøñã´zõjíDVãKJ }ûí·T©R%ªQ£†¶`ÝÿýÔ¬Y3½\£Fâz4oRìZS:ŸÕœ9:˜=%qVÉîs$á™ÙGNMVˆ\M×B¯ÑÕ«W“PÚnsºMzZn Í,ýæòæ~°«Q¹E‡Ek‘•uíì5ŠNWžªÌÈŸTéY…þüøOÚµw—¶äÃ2ă}›®6w¢%³×·…=®3 m®cvBë•ç#ë"Ñðª*THÇl4iÒ„Ž;¦ßˆ ¬þøãZ¶lÕ¬Y“z)Ô¹sgzðÁ©~ýú®e¬ðpºC}.0x0ùÿö›NžÕ°!…=òHÊâ¬Æ[Vî«‘”;4Š¢Ò<êZùøù8 ƒÔĶ¤Æ‚à®áæ`hÞÓUdº¬P§lɲT°PA‡•š@÷È+‘äà—æZœ¾Ñ°F–>«@jŽ2-ËЊŸWPíêµõ8”,²Ìx,×ÝÝ|ózÛbÏi,BoýíæDߘ¢êƒ> Ê›7/ÝsÏ=:¶fåÊ•4bÄsµqãFš5k–R»wïÖËŽ=švìØAcÆŒqu)v¸î6l  áÃéSµ-ÿ_Õ)®ŽK—gÌ åËS¾}©´šV®Bê¡ÄÚ_[·&¹¿ÅK¦mˆ&¹¾äÖ›Öí¦^?ŽçÁ霠—ZuêЪï¿OÕ1d4ÞþpFp;‚ÜO§!år8å Šëúîn€Ý¬Ä¶b™ÿí€èÂ… Së6­éÀŠ:]BjˆŽˆNs­ŒÎŸ•à¼UéQ…~ßð;üçd‚q(S:NaVîkr÷‚àùˆÀò~|X`}üñÇôÙgŸÑ?þHG1샚Ž|WÈuU·n]:yò¤Mß«FýðáÃÔ°aC—ëV.~kâ<=1û÷“ï‹/RàÝwSž¯¾¢U/졇èÒìÙöðÃ:îê!õÿ5ÿ¨Zßþ½{é¾AƒhÈdÊ®Y³Æq:Ä$@C™§ÿù'K.Hrçû2éí·éu~Ss ™?Ìc¢c²eûi¥ìú£t¹L>ºT>ù6Q¡Qú·‘ÒÆ*«˜»ø/ÓEKt¯®½èô_§éôöÓ)^wP± òËí§sh¥–ŒÎŸ@æ.›6oÝœ`ʤƒÎNá-ÙÚ½XÞ ~q¸~CwîÜ©sçÎ¥gŸ}V‹¥ ÐæÍ›©qãÆ:ÆäÀôÒK/QõêÕiÉ’%º.r³WïåËäÿÑG”§ x÷]ôj¯^Ô[mìê˜1º§ ƒUëÞr‹« qß;î Í¿ÿ®çAÐuéÖM[e:vêDû0.—»ùpeö½óN=½EË–Úê–”…§}»¸±óºvé÷½C:tèþŒÿÕjÔЂ‘—u·]s9Þæ¯ë×'ZOr$uNLnSÛƒv:†,»‰âÜ%J” À|:G’·ïøeªýùvlƒ@§–Ó[OSù›Ê'ŠÁa’¤7%gŸÓ v*_±<í_¹?ÅËæέ{"P=µpø›ÚÝäµ >‚òK5)E¿mþBCC ômÔìI×]ð>D`y,¬¸E <$ `êÚµ+ýðÃZD5oÞœÆOõêÕ£uëÖѶmÛè]%šÊ•+—  ¸VJ¤,_NÁƒSc~»vQD“&ôªðå—éGlÝJ£ðÞ;ïP¯Þ½©wŸ>ôÖĉZ˜0O?ó =9|¸¶ÖŒ9’†?ñD‚eÝÍö¹ç¨‰†'§_xž1Âe}r²BMŸ6MÿÿèÃõÿÝ»ÓÂo¾ÑŸñ¿_ß¾ ‡Ým×\nåªUzüw·w$uNL¾Y´ˆªU«æx Y „`Þ¼ r÷|â Zä[TY@q×oò™3gžŸ?>uéÒ…^yåš3gÝrË-ú‡¸J ôä‡3;é×÷SÿýÕƒ$H µÜ‹ëÁE¯#‹ð!t±Cº–7¯~9Ñ]‰dƒß²e ý¦„Ä+£FÑ€hˆi¿üò‹[·p7Ó?5KïÖ’ôïOwß{/=ýÔS´F Í ¯¿ž¢íö¾ývþä“z9t€PzA ͱ£GÓ’o¿Õ.½”Ô9lI+]ªTŠ×™™à¾€‹²rµÊÚªã :pêOûƒvö­¡‡ÌI-ÞåÂÞ TµsÕ]ßÍÀáëçÏ“ÏæÍäûå—”K½¸ÄT®Láê÷@áቺ÷›3Ùn0Î}JêÚÁÍüÛíÒª MŸ>ö-ÛGµÖNö¸±l©º¥hÿªý©Î¡•Qà³›bê~AbÝ —/PñÈâ:U‹'ü÷Qóœ®;ÆMµ³¨3é¹¶©©kß"¶<XžUü0C•Mª`Œ™¤Y;v,­X±‚>ÿüsÄŽw¸Â>úè#›ÅqìáFÁïôi úäÊóÅä{ü8Å*DWÔú.ôîM×Ê”‰{c‹ÏÃâX?àŠDy@‰²›«W×bËîÛ³‡òçw~ '7?­”R‚V<ˆKô”LÉvoÂ8ˆ¡¡Ú-'µk×N¯i-ðཥNbK ܆;¶mKdÙrwN@VÅ‚¥n°›5jFŸý𙎵IkʬÀÿZµ~mùªýüãÁúiJ KO”ÅJ% Æù8x|W¯&¿¯¿&ß?ÿÔ/œüJÏžqäå:qBË/)fï³À@"Õ û`ÚÅ‹ä£~Sî¬ÉÕuQ¸0‘ú-šBŽÏ¥K—Öyî¦Nšª{¦dÈš‚!Ó”C+#2À{* ÿ`:uá…D†ÄeòW"+V=/}Õ3#ׂ‰®{äÑ£ä{ö,EW©Bþ«R]/R÷iíL͵͈û@Ò4x>"°<U:ÖJ•mªüIqÖ«qª<£Jnä°BÌÕ§Ÿ~JS§N¥)S¦èÞ„pbZ… %¨óS€%K(P °\»vQ¬^aê-íü#ЕjÕ(òønÂf>›ik‹˜-ý¥{1¸''«}yáùçiÞüùúM{%2¾Çãn~‹-èƒÉ“é‰áõ âñ—ŸÖË\¾|9E‚ Ö¨þwÝEcÇŒI4/©ý‚›é?ôë;\ŠØ'Ѝ‡öÿq¾“;'ž†Ù`7¬Ó>œõ¡ŽµIMÛ¥¨{²ÞŒ?)dõZ<½Wš¬Wà쮳Ú%š/8ŸëÅ¿€­[)PÝo~pëñvTê^AqùèaMàóÈõTC9q"ùª†Ùï×_É÷­·þgç¿JaÝè.](Z݃æX¡‡…ýîß½?­øi­S¢³ëû]“MŸP´ZѸ„£©È¡•à=ÄaÁ wôøQjP£A\x…ú¯G¦pºîyT¹^±"]7Žb ¤\ê%Ìÿ¿ÿý·^¯mjêÚ÷{%Ċ幈ÀòLL‹Õ0Uz©‚Ì€ðÓ! >/X°æª²™ªU«jkU·nÝè™ø!¿å&pÆÄP€z8¾óùoØ Þâ£(²vmº „Õå¦M)*¾?À]½Ëbœ{—ÍPâdü„ ´ióf-~ ^0 LP,ÄOÁ%VE=D1ÞÄÝü‰o¾©ã¢°^Lg7ZëÖ­µÅèıcÉž@¬1ª¡DÜ”MRû…å°]üçB º£^y…†=ö˜>WØïäΉ'Ân‡ò!à@Ç6£ê½«g÷n%ÞÏ課l5~ï7úùÅVtàÖ´‹ÖËP劕u¯M3ñz½zªÄ=\C¹¾ù†üã-ÑAAttèP S¿3ˆô>Ìm YÂîEüWëDo´§¥'u5sNÕÁ>ÚcåaZÁééûŸ¦G†?B[çl¥5HòØ!. 2R“C+#2À{ p‹ÂM¸oß>Šj7åÕ›o&_õœ úé' X´(Áu?¦^¶®U©By7+>V5R=‹bÔï×#&×6½÷+–g#Ës0_†¹ŒT¥‰*O©RY•)ª@1|§ ^Ÿ ªv{5ê)æMõ¦ÿAßßHžnF›‡¦Í5à;´æµìÙ2ÑØnpÓĨk®ïуbUC¸t)¯]K%gÍ¢}£FQ¬jh}1.`îÜÚò«‡31Ýî<¦!¬Mª®ŽçŠO`¾¨$W×ÑÏ.Åtñ`Ðë5¦!÷¡Yo̢• SH{÷â3°p U¼µ"í[±ê?P_§mHŽŒÈïI«SŒþ^÷·Î……ó}]ßðR¥èúÀÓ½;ùlÙBAß}§¯{‰™3iÿèÑ™/ùsoBuݵk(A‡&«î±^y6"°²7ß})a/ÁA'®N©‚þó©òŽ*ëTA ^W•yè¥öá‡ê´ øAÚÉéüÏž¥ O?¥ÀyóÈqVùóÓUÕ€œ¿ë. Sb&?RÃâ…Æ†ÇéâfyðYOGÇM¨}§\rk§{hŽö-ÚÓ„÷&Ðåc—©@¹Ôç–Jv{ѪÁHåàÀHÇÐò_¨üO‡iù;]â,Wé'7Ÿ¤ð3áTºhi—@1Ó”°ÎOýž®5iB—j×&ºûn 8p@‰õ»ˆÿ}Àúeºk·Âë1]9vÚT]{àé–²øãg7!,jƒî¤‡ÆZþèrê<¥³[‘…ekô«A î] sh•ª_*Ùs–Þ ðžFáJ…éü¹óº'! >7>JHEªë~1—æu7Ý6Šf¡“šk›‘÷ˆ,ÏEZ¡¬Ã¶PÙÓUå9UÐÅ æX¯àÄÓO)Â/ïUލ2D•™ª<¯JÀÓO?½óˆ€oh(ª·°¼œ(Î &q¼uSüÙ|“7ÅÖåÎ=èIøž>M RÀâÅ[¤]¯QƒÂûôI³Ëí…¹r%Î%pñ"Eôì™Ý‡’ˆÌ|€Úïö­ÛÓû¿¯‡Ciöt³ ÛÒ)T^¶—‚Î…ÑïÃ¥h+¤b¸eöVLtá§½étíé>ÞŸ«uÖ»… ,äô—…’ÙprCˆÏ‘+RDùò >£.‹+—åË!Õƒ9h0»’L—NRuíg[À™"‹E",#‡¤ëêo٣˨˔.nED,]È¡•Ò“ÞÓ@/R¾næß®ggüùÆu¬PA_ws€hS qEJ¯mFß‚ç"+k0ƒÕ RœpŠ4æ#Í7Æi£Ê5U>PeųÂ…oV9°d!qÓU.¨k« ­Pê™{ófÊûÞ{”ûÇÝÆYR,¬Ì¤£üCæ¼0žŠÿúõ”÷?ÿ!uÌÿ0ʽr%,]J—•¸¼^Ý!ž¢‡QîÕ«u°®mÛèÚãg÷¡8ìæ¿]¶ÍœK™± \oôÀìWš9s&Õ¼³&å/“¾ž,¬~¸‰ÊþvœV½y[²õKýq’ª|·—*~€Â 桟ŸoAûºT¡ˆüéÏr›'ן¤~ôÓ"É´DÙ]ð¹ÃtÔá߀íVt>vÃÇ1‘6îêšÿÍzvBTnèqØ?-²UïfjQX²:Lê@•:U"_Ëjˆ@øÚwÕ¦ß'ÿN n c²’ÂÌ_(Ä;³¸› À¿h‰¢z,Â.¸øëÏ××oNÖNsÌ@›¬¸ÏFVæbÆS!wÕÿ©ÒM•‹g±Z_âj¢*WTé§ ¢T¿¤8KVU&©òÅÅa•ŽŸŽnmèIízóF>«(H5Ž_}•(Î*¼@¸7#Jge +Óm<ëiø>LÁ/½¤-t‰æíÝKAJd^~ç×`Ôl­ øæʽv-ùž<©Å‚VÃï¹'»'Nƒwg–À2¯óí·Ý®Ó}옿#ÍV,SX•ûõ¨Ž¡:Ôö&ÚzwÂ\Mþ¡‘ºnAÕàÁxó’=|ò ]¨X(C…ç–é[¨ÚÍÕtzÜ÷h`Meö˜5ãœ8ÎØ=rÍúŒÓïÅ%2%uû5÷Q÷€ŒS±X±bôì£ÏR€_}ûð·T}`u}m÷„ׯ÷7¦(‡–™>5ƒK{*§þ<õÿì] tTU¶Ý•9„0C˜h@ ˆ€€ZF0›ZÐå÷+~£-N-¿mù j7¢2*, s% ei!È$¡é0ƤRIåßsß;•[72‘J¥ÈÉ:«R¯Þ<îwÎ>û Et BÝt.èäu2µhHOÕ–çØ–f\WçAuŠÐsÍ–~VyËÙÂÀŠâï„Xˆ¢´ÞHá …SIÎ áwP85¦K>J8åBfÀg ”à_„7‡Ù„“Ræ2á?ÑÂü.]BÍ5kPcáBÏ*sØ0dp•娩*°ÒS‚®:_ÀÓ,HWàŠ-`óføïÛ{ÆѪƒaÉ*P¾ÎÀÓ*öéÜ{‚щ–‘œˆu¥(‘j)Ík'ÎÇ-¼\‰ãì—›‹&V+¦õyk?Xšê!¤^Éy70E}}Z¦ö¸›qîäúá§Gb½é„Ô±Š<þ„ž¿ŽÈeÀ/Ë&ATFLm|?î·øù¾f¸Ö¤rK!‚Y#ppjã)L0U+v=*¡,.‰/MªÆU4¢¨—”’Ž{³éùáÏêB0}Êt´Ši…¹ æâüÞó¸ÿõû%8âùPt²Ëº å¯)Åjh© ðÄ_U6JҹУOBÕÒjŠ…žFwA*ï±-͸žú²[m…­²–ÙœAV> @V¾6¾n®Æõ$£Úþ„/~·pzªÓ>_ üEá”»:,|£ð?Èd€‘J¤\ ±Œ)eHÑ«wa¤ íæ¾xžæ'fZ³Éž=¨=k’àìûîCFB®ÇÆ<+À‘êà07ƒ*=Ü­§ <ýíȧ˜ª<ŠXÿãð9þû÷;iÜ8LlcÐâÅ•½)NF'Mk±Þ~Äù¡‡€é\QF'&‘ý‚Åþ˜ €]_n xÒZ„6 …¥˜¥Zhfd!TL@"žÚyC¢ É"`e1ºÔ¶.þÕ¯.µ©#›5g“¦*ååäaßßö¡]›v2zE@„ˆáäÁrÕ.G®»R­¥¶«) ¦4ÅÒ>@uÑIõšÜ0ZÇ´ÆüOæã‹¡_ Í°6è4±“”) ébGÇJVòkÉè?§‘ZåQ€÷4˼˜)½AÝ…^*U ¥«ª—帻Ú1nµy¦¹û*QWÊ©à)_q=l¢&®óÍix¼[ ² é–rþ¼MT¿Oœ« 0xW”ë fäXáÔ¡•¢OôLûRøá$õ½FÔ+ÁtÚ¾<Óy[-Í€Mo±…=ñþû†6KÛ¶¸BéÀ>}ÄÛÚòÍxV®* ª’Ùë/4i»ûnäÜѬdΜ)‰ñžbq11X4eŠU­‰P±Ž5kÔÇOoÓq+ŒßÔ©¢Št²­V|³yþ÷½Ùè÷Â}hÚ³éM§§HUËm'Ñzíq4Þwa§®Â?Ëæøª)"µñÝGÊÔ˜¹¼vlõ1œÝq£¦Žr+jÅ,õZPÓ0ê§Î…ñ$SAm#ïжg$"iS–¯ZŽÏW~Ž}[ vL,¢ºE¡Û3ݰrÄÊb5´Êªïiv%í ìV;j×r™îÕÛyòq¯6Ï6w,XQ©Ie“ÆåR…¯NŠWQ*èÌæ'!_Ñ×ÍÏšæï <•d©œ©Ãʺ`n¥‰eMR g„Q1Èû‚ÒˆvñŽo™´ì/ÀXmà÷bgÖú5, Y£Fá?=µS0®§]•£WuÂ$'ɯ²Ù\þžO$VJ›ˆý’5i²‡/ÄÁ¢èVwÞÁõ9s`¯çlé$ÏLJÜJü:†ôଠ€%÷¥ƒ))œÚÀÜÛ«/Ö}½ë_݉ÁŸ .¶ ËÑ!wàèc휑…ú‡.J¢:)®×9vI¦Û­úAr«¶½v©¥ÊcÔCo×ë»0 n"#"àŠ>`©}‹2O¿Ft¥—ÿÿýpôèÚ{îÅúÍë±vÌZÔ­ÆÝ#æáì|sçM5´Ê¢ï‰FéÁÚuj#¤Fˆƒs¥÷¢Ô÷kµU[YÌ]‹A ]•«„? ýÞÕtjýBÊå›PœØáœ 4ÇQ­(²ŠŠºbx=i Õ4¿s‰—QGü«#(HξYø‚,‰›uãȃGú$p•›DN«Lö‹¹vXúÌ3ƒZöë'µ,fµâEuým­ªß‰õÊŠ¬! íäA—³Ðà@:¢¿ú MvŸE›ÕÇpèñå–[(©Ý¸p¦l@£ðFè|Gg¸¢“ôÉJîzôªªš ²t€Å/YÄÏêyWOœL;‰”ý)Hý2~¹{¾k&®ÁÀºYeQ€÷4£óû\Ê9´ŠnUHަZþ Únµ¹`ÑUÏàŠ¤±©¯µ)uFÚO8èéF@d0Œ¨–  jšó +›@åÀr•ù%Тò´Ôõ¹™Øç@óÿ s¸Íœ?/£4 ë ~Õ[0ÚÜœ1—AÀŠJw(jµFäj‹²Î•³÷/¤ïŠ[ÞˆŠm7€&O~z³^½A- W+µÉsUMº²|ñÀÌ|ñE),ê¿}»”¤ÃCBר|©!ëåËR†!äðaØç̓­[7XDN÷ýßâ­Ýi*yY8¬¨ÜçŒAÜîÄË/¾ŒgŸ{ûæìýÏÝ[¨äÿfF¼*[Å ;}×¹'úa½nÅÎÄÀE >!aaaX…PºU|ªéAo¸Øt.¥JÞfY š´?H¹耡²)zú¥t¬Ø¸BV>:ÿÑB «, ðžf$ K„ÔéÅS­ õ¦s¡Ú*×ܰÌPZÀ•i˜º^mŒô iCQ D6ÇÁ41Ø¡»;Gv`ŽÃ ÊG[n¾æl¾Úº±ùhóà–ª[åj~ºé)ER]§”(UÎWÖí ðIÂëÿÎéÎ|$}–:‚Å´b¢±?>À*ùcü º)èU®*£¼ X©–׬™”b ÉKŽq˜$ÀjÒ¾gÏÂ7- AK—J½,ŸôtCtÝ:Øî¼S¶C±öë'AWyÔÁ+ÂT}3Ž@0ȪH€%÷i^žã|éÕ½žñ,Þû.Ã%O§4 ‹ÍVÃ_ÚÝa®¶>¿ç·ŸÇ”qSY;Ò \éävo{°ª:Yª0&ß\RÏjµÊ}B-¶‰’˜1X²j‰K ­²(À{šÜ|RöÛlÞ¸y¡—Po½?V[å™»]¡›ß©ŽÀ—«¨äí¥æ¸ÇÌOuýÌy3¿·@ " ôŒÈE¸.˜ó¢(Y& @K¦9í}Â߀‘–̆A2ÁüÿßÊ2O+˲(ó) È¢í£§>U ý ð®„3(³¯¢Œ!F¾.¦,C¾“Ë}C@1—n²ù¬–ôžU‰Llo^LL¡ÁyM›J§h•ï™3’àN² ë×Ãï^éÁ~hDµ ‚­S'ä‡z¿D?ä(„;".:è:x(lâoά9ò{YA–;ŒÁÕ¹Íç0eÒ4mÜÔ®T€¥ x㵡W½é)g˜TÔ#^JØCŹŸŸ€@¿@$%$ÒÐ*‹¼§U’_sÝ{v—ç€Þî¨"SïÕv{ZE,•ØÞÝöµ²\6€,"´ÿŸ9¾ö…st‰çAÀ‹TÍïP~£”#ñ›¨'ÇpGM7a'ÜüŸîcÌå¿\Äv™¿ÛLçí*.MÈ€‰¢lÛaôœ#ÊÃUÐFyÄ:beÖ3xV-ÅÀ_¯«Ö p6ø1§`Ùò;Ý$èmÔϪšS`‰E¶h!ÚádMœ(ÕÞƒV®„ß±cðýì3ÙÊ+{èPäôî-µ³*Ó\=U¯(ã’tU ˆªG !¿Ï5×N_“éÂâÀÝmDhß1s.¸,ÁU³ÆÍàŠ¶}gî•·‚+ÕÔ~yêý,ŠfQå(9,º—<5ù)Ä´ŠÁ¼…óœ4´J«ïIFQ·Œ#¸ë»Q~]d¶ú^Ym·ÒÜ™"l`~'27"W9¦3AÁ;”áêS…%H~›ÀÕ^Q(âwQMy" PGài¹¹,¶£æïÌß)%I¼+"›/ê9^À‡ õVs™%iÈÅàŠIò´|Ò® B¨tDïÄ£+è5 o`DÖ왥‹Å î>í,M¡NëC7 ºIz+Ïê–›Ø'´²=b¨šÀU@J üwí’©ÄÜÖ­%!Þ:dr££+­y´«,}\yÞ$Xéo*ೌÃðß GDHfÏ™ôƒéxø¯#²ud¥ìÕhÝÒ¶¦aÓŒM¨a¯!Ó‚¹"`E|#W|­xsôJ7UÛK\,è83Ø"§û ù ¸AhÓó—8khE÷-¹¼§˜=ÏŽC‹¡C»²’”ï™zÃîÛá\¨êV•Ž‘»ž*0"€Â* °8Âd1×ËÎUm>Üy°ù*‰PN)jECÕ{_™¿SK`Ê0ç±À¢ˆV 8G¥üÌõ*¾#Gšhú(Hí‘åµó^ ÜLRxViÀ§b¥6¬5Ò–l ÔÔ¨Ÿ¿‰U«Ò›Tq8Pò°(’%ÁEµNœ€ßûï#hÙ2؈ [—.Ž–;·ƒé ár‰‡rÜCq²mö¼ÙX5lú¼ÞÇe¿;w™íW¾ûè;ìzcZµj…ø¡ñ’sE‘U®dQ‹Sƒ·KôJ·¢DT9õLÜ;•øÝ¾m{—Z1q1%R€÷;ñÕ œÞtOO~Ú¡à¯òðôÖ7UѪòº{ëöºóµœD5‰$ƒÐ­ h²Î©—SªÐ¨Q¿û™ãpjpgË%õÈ 8ƒ³³(O*€ÑŸjŠÏ-Wãñx[y˜þÐô!`bM`´EáY},›epÁ,Êô FU€%÷ƒ7•™Wš‰›ln‡Ò©ª0`ãFÉÍò;~܈nmÙ"ÅJ³Æ»m€ŸK¾Zu% ïòÛ.xû¥·ñÉ—Ÿà«i_!}B:bÇÆ–»9tiŒ€ií~g7Î&ŸÅ°!äƒZ-ÈiAWàª"Ó¬žnªˆª ¶TzÊûÓ5´Žn:ŠàÆÁHþs2úÏ-ZÞìòÉËØöÂ6ôëúuë;À•Ê[õ¦ûg^^I,UËrss`³åŠà{úñr'À¢¬{`ÊucqÏ ýá ¨ôŠ?“U”QDK¿úy:UßJÿLLL/Žà®›š.´¿ „ŽFÔÆŠÐŽyVëOÄðã.xVœJep•«Ìïö ±»ÑHl4;>9=$õµ$OëèQ®Yƒ€mÛ  5y2l;{\åá­6µÍ_•4¼iTSL? ];vÅ¢OaùŠåhß통«P ÅÀŠ7SoAj?=Þ!"JàŠœ€§Õ‡iõµâlza÷W”†VÒö$l[¿­XøÊ4"¶óÖ7 G—ßtq€+Vñ÷.Ã4hPlG\Üxñ½ê¶3ÒíÛo·àÚµK²ÚÕ ÆS;UÏQ%!µ!ý+ *׊Ö%Ñ÷S˜bä7™!J»‘B:I?d¡p_Ã|Øò±Áãå2ˆRÁU®âjÃg”b}ª­Œ&Ûì<ñ„ÔÌ’­¤$$'#xþ|á’U‰&H=.o55]èêáKª¾a}ѹ}g¤LÅê¤ÕX½bµlݲ_K4ëÝ Ñ¨PâFÁ9™9°^³âÒ—pbã ü¼ågخڋ!† a½†Ž(„ªÐÎ+•cS ®Jnú±Ö£Xêþö»aÈÈȺYÌ{Äc@«Ô©Hy=ã‡æQÍç§‹½%zEÆÇ©OŸÞh×î,[6S§þMl³çHΔÅìöÿü-Œ;:4‘÷~‘R#Óž•vÇZq4‡ÛâPE_°ù©ÕU ¦G—|Íi|•a,ã£|@Au!”ùqdˆs²²•ùù)˰›óð7×ËjŽ›‰‚¶9j‹°JÛ5U½ZÀ“~&ÏJL¸ç{ࣧ ¾ •æk릧Úæ 0°â}´cÇŽ«½zõªƒG9¤“-«³.^¸P!Ë©ÊFà*xÉ)é`¹zU0ÒÐ*¾^ƒâÍm©$u6lØP‚z8¨ÈV9¥1ÖÆ¢s„ÊûYG‰UÁ© »ªÎãÑ4t^ñ<Ô‹üàÓèª@$;S›÷VK–Üzãã­s>Ι™™¸xñ"æ.š‹uÖR€w‡‘Èìö—¶#}w:Æ ƒŽí;J`E× k¡Ñ'G99ºé ç7i'±Ø¬¬,\»v‡_@bâóâ7 ¦OŸ‡¨¨Ö•½š%2ª\¿~’’`üøIhÒ¤¶UòØQ„ŽœŽ%G5’u+,99½{÷&EeŠÚÁeá×a<ÿ™¢SbswŠPWA'ã‹Â€Cåñz2é‘Íœ†? œXµyª‹ùV¼\g¼ »² þŸ×÷ÿÙ»¨ªªuýqQ@P$Ùˆ$"¾ Ì“yŒòŽÊ²†•åFOfy²F¥Þc¤Ù0=fzÌÊì²sz€ÚãÆîØÃ¬c]s{Ò[÷¦f·»ÁsK5ˆˆ¼A‘;ÿ¹ö\Ì=] ) ÌoŒ5ÖÚkÏõ`¯ÍZßþÿïÿ~Uÿ$›~òé¬>®ŽRØÎï$;ØŒX¹uV§Ñ”ÏI­ô0 …ŽXy=ê† Ayj*j&NäÖþ[¶xá;«>«©h– A‚pÑ\¸…Ó$“,zXÓ$ìä}Éi)¹q¹ÚGN<,»Lk¨v€jVªVp…‡‡#ev ÇFÆ_3<à[óZP¥à¾öaÇòñÁsŸ@dÿH«z ËÚ«Ž.l·‚øABÿ6¬–.]„gŸ]Žgž™Œ›ožk¯€¯dcüÚût=@ß©ââcØ»× §óßQT”¼!üoQ;1è¡òù¡ìÔ¢!-&L7åÆÌrôJ A>ä´œœ^ JETÌG:®‚rõÒög¥ýúÀ“ ‚xN9ŸïÈ¡ÀcþFßÀÒY0tVK1tVâœdO­¦ˆÕ¯ñÚÒð°¥ ÏŽ‰š.¦Ï’ š2$EÑA¦D¤K, bEsrKÞ§<Ëâ}M¬ÚMu iòí“1$vþ²ÁÓ>,.¬E¯ «CßÂîµ»qhû!Lœ4‰×&"¸W°YM*û É-’:KäJ@MåÒÿý½±±”.\„7aëÖ p8V#..7Üp#[7#,¬uÉï…PVv û÷ÿ€¯¿þ{öle×*£F]ää›a³ÙLÛ…”ýì:InË3“û "$“!‚•-‚ØVD±äu²èÛGÚŸêe%O€§– ±½œöS‰šy^Ù@ÈD`J 0Ç­³:S lÿøËC@ÎɆó”ý¬ZJg¥S„^Œ),lÐgpFý +–,ÁÙáÃ/¸}GHZAD¡dâ¤NjÔJžêÁ¨j«t*°ý`•.¬¬¬Dyy9ŠŠŠLø’òî?bÆD%DÁ×Ï÷¢I?}þ\ï¹pxça :“nž„A1ƒÌêQ¡»’Mf;“k{cÿW%¦kAéBº¤ÉŽÓ§OóÔá‘¢#(:U„]ß…‚âøú£º¢ý£ûã¦7¡÷˜Þ놠Aý$ÅCYî-(7q¶ê3ؾKV~u²W}FDB)…Hº&’!DFFzTøÒ{gÏÖ¡ªªš/Ñh+{ÊóQWgÔŽÑq)ÝG§#k¦Äyɶ+rôJ­Ī#^GohVÔÒ$ãR÷ça»° Iì²Îªø’tVó€Üƒ •„V~Vâµö³Òà•„åiiÜ#‹¢YÝ÷ìAÐòåðÿè#TΛ‡šÛoçdìR!ˆÕ¾}ûxeýR”oJÞr“jïãk´,ԻŚz`S /44”/‰Âê·Þp+Ÿ‹²ª·„MöB“£êCYn\ÝÕ¾kªð•¼4'beUá«VùŠB«nVÇ—ÏCn.¾rE°\,W«FÁí:zÁò&˜ÂöU@Àý@BCg•„ÆuV¹½UÔJë¬4 °Ä™ë¯GÙÚµZ¹~Œªws¹Ðë‰'Ð}»*çÎ=¯Ò°¹‘1–¦£GâÎ;ïä7(ËÇÆÆš7)ñðêˆ7, ïFsà…u‡úP§¹\]* ¶oîƒY%V]ù;ÞX…/}f²wZÝ+ˆ®(` Väû‘սɊ\©E*r°LœeB¥^ÃŽx;#ÁºÐU¨ob;ŸQ€ï@|`ŽÜ:+Y¸¯¡ÁAѬÒ5kà·cW­âѬÀW_E·œ”/]jŽkJ ®B¼OªiÓ¦ñèUBBnºé&¬_¿×3b'nfšdi´s€§;=¼…u‡üPW­;„ß–üpV-:TÛm×q>Tÿ2q]ès–r¤J­òU­T.&‚ÕѲZ¶*fé¨è ËCˆO‘»ÚÙªi³©;D1b5ݘíãÖY²ßÞš4¢³Rm´ÎJ£y`77ª2¬<ŒlQª* ƒÁmô¾r“S«ïT=“÷È#àðáÃØ²e ×XÄÄÄàî»ïÆ*Fäî½÷^;yYC£%ÑØƒ‘ÕÃ\žÔªÒÆÌêCYÛkxB-:Q+|åûKc•¾Š^ÉÇRçj5°•ÍJg U2:2Á’É” >ê² I:g±Ln Œ\½ëcØ.œ©þ±X; ø¡ÀØ^ÖY Û+•j5¡¡Ñ$ê"#Q¶|9ª ¢hÖ7ßðÆœG¿ú ¿ÜvÛy¿ô­JÍÅMqÅŠX·n/^Ìu.¤q¹õÖ[Y³fñíï¿ÿ~_ø¾- ûÒÐh 2Ñ"4õ`·2µJ;j»ŽKCS¾VU¾ªømê8êüBË ‘`©¤Jn–]`»~ð4 ­“–ñWàÔb =jzd/ç_n6ÞNóZg¥ÑzèÞ[6”¾ö_|AŒ$ ÏÌDh^Ž?öjƒ‚xêO6Ø#ˆMŸ|ò –.]ŠÔÔT¬Y³†>Ξ=›»òÊ+ñá‡ra1‘5‘N!è(–F[@}ØŠï­ðLkì!®í:ZV×E@½¿–`Éûmj¹³¢£,™XÑÓ¡*n€ÉˆGÒ}IHdíf¾}ÿv8ßvËÎt!§ÀA«"¡¤tFŽK*öH*eëüÝŸÜ|º±t ÖYi´È|´"- éŒ`=o³!œR†âØ¢E¨;Öƒ\ÉÍ‘wïÞx€G°(BEº«‡z?ýô_GeÙ 0õWr:¦³þzÔðnXEa›³F뢫‘ ÖDG"X‚\±ª±'ÚaOcS’¿ùÞw§‘vÈœ|ÏâØ44~ûUŸÈ&ƒleÌÊ8ìØÎ‰uà5 ÓLßöߞ͡E›¹i´ÖYi´ ê{ô@›ß–’‚ß:eä)jþ|ÏžšéÓÐPñ0‘¤{ë«$—øšDEEÁÁ¶;w.¾ÿþ{Œ7ÎòfÕ¦FC£= ¿{ …`‰>ƒ4Uge½Í~­O‡+Hs:àp²µÑlÊ7æñlæbSNAâêÅÊ÷~û€8Ìù]_d;³±nÝ;˜9ó>’W cS Û9}(úʯÅû:¨Ñª /Õ› ÿùÈ#¸öÓOÑoóf„ýùÏ(ÏÍE邨‰áÄJTPQ•àÈ‘#¹ÆŠ@ëÈÔ133“/?~o½õòòò0vìX<üðÃ|=Wý±44444.ÞÙ1Ö‚\u‹€êÿÍ«ç䊈U:‘«|F¨¢‰T9øœàÊwp’E„  H•Ý\?{C!Ò²|Ο`ûÜÇÞ a5ZòwKhµˆtU»çV=5¹Òh5á© †kÖ,äÏŸ:¶ÜkãF„Λ‡ú;Q]UÅ£Uä)tÍ5ט*ÙÜ‘\­Épô–[náäjÒ¤I<¢5eÊTTTx˜ 6§üZCCCC£yðv‚eF®ªZÿ·zÕmG²³!(¢UD¢\î×ñÑÆ2_Ï–‰xñHCŽOÒ rœæ€Í7ÙÎz"Y?°·¨ÑR ›üÜÇ–£VšXi´9DIºOPŽÝqòž5ƒ#à»ï`›3ÝׯGMI‰»­ÅY³ôZ+2u$òEZ,òÅ¢hÖ]wÝ…W^y…k²Þÿ}ÓðQõ¾ÑÐÐÐи4x3Á’íÕ¯nu" Èøº§]îA‚TAšë|Í)•("YD´âò\앃‘¬d>žöÍð= ’ÕÉ‘¬ó,44Úr$Ê/ ÕcÆàðË/£lÂøž8ÐÔTô\¹µlYô$K¸"ñÅ|¾dÉ3ÇøøxìÚµËÃI[“, –CG X5¤¹¢ Áô|‡ù¦©scÝÐeÁˆ`QT‹G·(•˜ÄˆV¾9l}z–ƒï;;3›ï‘*$’Eú4m¤ÑnDIôq£©~È®Xbj©ãïÞ™™è³`Î8`’,á#DéÂÂÂBž>¤ýÒDDŠ,†êÑÜUG²4444ZÞ*r7+©ZPh®(" £r-SºÈ‘xO+A¶âi|ÆÆSõ`âÌD¸òÝ„+?™%®<Ҳؘ™vسìplw£Aƒ%Û0hA»F›ÂªY.­«cË%³gãÌå—öz5‚¶loq1ŠŸz µcÆx2N˜0/¿ü2ŠŠŠxÓg"SO>ù$Ÿ“»;ªgŸ}– â0¢FÞDÙYCCCC£ùðÖ;§ XUsÞœÃS|$fç•ùFÔI+‚=Úî®4"\"Råbë¨Â09«!ò•Cø4‡ÇÁ(2FŒlþ#ŠEz,½w‡µ3¼†F«B­“¦ŠH ×{ô쉪)Sp쥗PÃuYa Â×éDuE…©Ë¢&ÏO?ý4÷Åzаo¼{öìáU‡´Ÿ—Øöؼy3À3¢&§ µð]CCCãâàËÔ^‘‰(‘(Py’"®Årƒ"R©D²¸ÐÝaÜóÝ)ÁhCƒµí1ÞÔc±÷I‹•30žG²26šžZ Ah XÝÐxû V…ˆ ‰¦¶B¼Î‰V` ꮿ…Ë—s’ÕýÀôýã៚òr3í7}út|üñÇ\wEÑ«Ï>ûŒûd½÷Þ{Ü+kÓ¦Mظq#úôéÃç§OŸ6Ó…r…¡††††Fóá­‹¦näÐNàÔÊ­¡"¸,6â$+‰ÆØyj+D‹¢[¢ê0‡&Ÿx¾WN®â¶¹¸…!--f¤Á‹ïݤóÒÐh3¨ÍRÏ#Y=zà\B W®DÕèÑð=u ¶ôt¯Z…šâb3’ÉÞ)JȈ‘«Õ«WãÝwßŰaÃ8zñÅy4뫯¾âz.š´&KCCCãâୋΫŒÚßPôŠ Cem‡›Qjo÷nc‘¬Éñ8¡rÁÐiÑâ¤(rE„æ<Š5>ž!-“áäJD°|¡#Xíµ¡­œ2¤‰HVý˜1(d©ü–[àÃHUï7Þ@oF Î””ðh$#?,jŸCÆ£ÑÑѦÁ¨èU8~üxSü.&í“¥¡¡¡ñëàmËGž'ú&rREÖ .xVº¢tÞ‘â‘Xù£°b~?º7ìÑRu!`y¦yDË'ÇŒ`¡ÞM²œûú¹'Ò`ùªç¦¡ÑÖÅë‚, ’EÑ,ßy…aÉÌ™äñ€¬,\ÆHVݱc&I¢í‡Ž;v`Ô¨Q¦Eº(¢E¢i™‘ «ªªÒf¤o#Xa.ÚÚcsÒLQêÏ$ZùÆìò>{ù<Ý™l’,ÒRQµ¡áìnè­<à'4XqN÷²ç("Wh X2ÉÒÐhX‘,ÙÆÁ¿o_œJIÁñ?ý õ¸Œ‘¬ðE‹€ƒM’Dèß¿¿I®(¶aÃ$%%¡/Û~Oº­7ß|“‹Þ…©Ždihhh4ÞJ°<‰L>xŠªEÛÀ3*E‘*j#æ&YÆx%‚IàîFNôyû솆ô  Wš`i´šê (H–•WVÀe—¡rêT.^Œs={"hÛ6„=ó 'YÂŒT¤i»ÒÒR¼þúëèÉÆNž<™G¶âââ¸9)¥…X^&YZ“¥¡¡¡Ñ4¼`5’†kˆBQ,BCŠ#Úè5˜œæI²(]Ø@ÊöÇ#W¤ÁÚf¤)ŠåòÇ}¸Ð ½Ò)B6…ª½²‚ YB—%Û8TO™‚Œ$í×AÛ·›$KTŠc¨½¤¤„·ÏùüóÏ9Ѫ®®æý Ož<‰eË–áñÇ?/’¥‰–†††Fãð6‚E8ïIbTýŒ(V¼dÙ R„† Ý°i}¯ì3 cQ×yQ,¬h£Š0' HöñH ±½&Wh:š¢Ñ: ÈïEØ ’%Ò…²)i#LÕÉɦW‘,¥ L¢DähêÔ©Ø»w/÷É¢c<÷ÜsX¸p!ÞyçN²h¬ƒŒœñR[ë蔡†††ÆùðV'wÔ¢9®Þe,åë¸À=ßè-h‚û]¹½°òÜÙ‰š‘}CºÓ=ν¶SÔŠ‹Û£e×̸öþs½òýo¿~í}:]D–hjÉR×åñ57Ü€+V lÑ"N²ÀHÖÉeËP;`Kû'푦¬¬,>Ÿ?>¹CDDV®\‰uëÖaРAxíµ×0zôhSÃEÇÖD\CCCÀ7,ó§0Y0 ŸÀmâêÝ„*Úˆ`‰t^¡Û@n¿+"^䅕ζA–à YÑÉàéA‘$ˆ|c=¥é˜ÒyˆÏõê¹uÈjêkWVVÆÓF4¯¬¬4½’tãÒ!Û0PŠüª¨BðbH–<–ÖU]wÉòY²En’%öOãèz^ÇÆRÄÊf³ñÈÖñãÇ‘’’ÂÅï¹¹¹˜1c>ýôSÄÄÄx\sa÷ ¡¡¡¡á}K&2ýo;¦¦&âÞÏDš­|ÃÃJÐ¥8¶<'Š‘¢ß¯mIÙ¼Nª¯ÏŒŠB`ÎŒ¾ˆûší‰¢UBmˆÜi_¬K§5€A®ê I‡ì½DZ‘¡çÑäªe ú\Ñg-“¬æl/ˆŽJȪL’HéBA²®¸‚ïŸÆQš®']×ôôtdgg#$$„[;‰ß§M›†^x·ÙÇ“ÐkhhhtuxÁ"2S—éBj*: Ž$"@‚( Ðëôt'²· Ò w$+£á5­KèèXE«žú×ll*spÿ+cÓ•†“;«³°nøÜ¥ [¡DŠ4>„RG¯Z‚¨ˆô‘+ŠdÑg/¢L"0â}Qaøÿì xe¶†¿€,a™@Y†EAE/ˆ$ÂŒ(W5‘!ʾ ŒàEÇ ‚,‚ŠlÂï H¼ƒ h¯^d ȨÀ¨ÃÎÃ.Kˆ! IÌý¿¿úïþ»È2@'9ßóœ§z©ªî®ÔÛçœúŽ­ì–-qì­·«!+Œ5fŒ†,®k¾k~Ÿ›‡-ZhSRöjM:ô^YhÞ“ uö{‰D¢âª@, 5[÷9C˜Yæ3âýÎ!¬ïìÀFm,ù­JT·£°uŽg¹ÊZ" #çŒôÞw¶SÀáØ8$D$83¬ÎªÈR‘È*v²Ç´˜û<ñ»çÔ d]™ÜcqlŸ+? .A– f² d™ž,BV®Y\¶nַ݇{õê…&Mš C‡ºtÈxXnÈ’R¡H$æUq¬ƒðŒ@“Ï Qm¢&$;ð3r¤3ö†÷Mù/¼dïí½¦ûAÕÅŠóé`ÄU‰=ÕCé*N¨Hõ,†[&£*aŽSrrò)6$_MžÌeùç›O'€ue²¡Äö¹rÌ¥Èdù]1ÛH(bö‰W–LNÖá9¿0Cýý¤Ž Úµ½•ššªç>ðÀz¤¡*##ï½÷ªU«¦×£ÅCûöí¢¡Û\ù(%‰ ›V©œáœ÷«HƒÃæüÿË¥ì/P3X¦ÿ)WæÌùݺÅ`dD N·× B£Ú ¢ö)˜ÒByn·q2Z—WºEi¸âk$:Û1s•m…*Ó‹U,åîí¡¤4xõdg÷q¿ÜýØåB~oÙ­[ãİa3ÆÉd”7Þ@NÍšz]fª’’’°téR 0@— 9 š>Y„l^YÈ2"}·hç`7âÛï[$‰Š£ñ?3*‡gƒ`¿Q±7yW²ÎVEwRõïy!BšÉ†EÔàClng¶ê¤Šãp(ö´ŠLø@+Pˆâšf°lª¶®Lº:ðß!“u4™,f±²22P&!á ¬J¤§ãdL ޽ôn ÑÅ×f&kðàÁ®QiiiˆÕ¾XQQQzHt»ví´–±–0Y0,‘HTXTœ2X¿x>³H·h±=ny2âó=2ZÛ1\ h1Û•ïd¼Ô¾¹èç žQ‘áYš –y?B¸ú º:2&“e€8SAÒ1µ$d…ÌŸÜðp¤õïÏ+¼™,úcñûݹs'úôé£û±/^¬³WmÛ¶Õáiñ`C¶»÷Kþ>D"QqR :¹S²Ø`NÈ9³uš¨?]g›¶Ä' qD‚§„……“½’l–H$ 4ñÿ«øøøð1«Zì˾,Ä¡‘Å*ß\À;£{Dÿ…¨‘NƒúSÝ^×™­äyÉØBgvã; IiÏÐ8Âç¡E›ÏÕ‚|ž˜`¿=C •HtE²›Ð¿•_©Ò‡ A©ƒQ~ÉTyûmäV¯®GíPì­b£»ÙÇÆ1pà@í•¡çrÆŒzßýúõC§Nto3W—j5!‰D…Y…°ø¿ñY×sÍ ý&12q5³VÑyÓ¦‘†­s´WA•‚/:´GÏÞ¢¯6T¢*ë^u Qånr2W­LøÊ‚fг»bïè.*2c»Ãëû¯FŒ@PV–6"­:jOš„Ü&M¼¾\Ì>þøc<ÿüóºËβä¸~ýz}åá¸qãÐ¥K]*4¯iÜÞí÷ ‰DEQ X”1¥r\€Zn]•X~äªD6ƒ|ö+ûêŸC»éíÊê4Š^Pµó°n'ð/€ýs|€U¾Ô iv7ïA€KThå†,oÓ{ݺ8>v,‚^xÁ –Â'LÀQK97ßìwe û«nö<Æû©‰'jÈ¢}Çë¼(Û!^ÆéˆD¢â @,ʆ,1æ Cf¶˜qâp¼¶à 'ø¹LÖÉlgoc¼®2ß’Ÿ"«1*º4ÒvO~LÖï6/~šáØ5?,.Q‘].d "±ë¤¬Ò¢üš55 Ç_~Ù S„¥˜˜ :T›ŽÒòpUµjU}u!Çû˜æv÷k \‰D¢â ÂX”,0ƈ”™(û¦ÊÀ+.y¦àÏò ×ö&så…¬=êñ¯€©Ñ@SµA]•j'w‡½ë'¹í l8¬û'°å àà¯W>Î.‘( eLd)–M–)³U+œ4aãÆ!$1Y·ÞŠŒN¼¥¾»îºKCÛ×®]‹W_}ݺuóî×\­hÆéˆUƒH$*N*,€E€1·M¹O—úà@• ÂUA,Y9°ŒC»ÿ˜Y ÿ++ƒÔ°`'î z5PÀõû WžõZnØ*HA®¥dÀD×\6dyÇë”+‡¬˜œ:|!³g£š­£eË"³cGï@ê;ï¼>ø ^|ñE \ÌX¹VKs»H$*Ž*L€EP²3Y˜ T™ò ÛãË6/µˆÿë—š,x ˆ¬´»Àë_¸N(àú°ið¯/¬ZÎoRjèÕn´klüáJ2`¢k*{È´iXϯ\éC‡"?/•âã6u*ÝvÎ6h ·!“˜û´çú^ÅD<ë ,–@`Ž3QÈ"±'‹U*4éƒ!³E ”Þ³á“'ã—´4ÝÀnŒHíõ´~àý3gÎ`ÚöwÞÑëšãQ‘HTÔUËÈ=RÇd²L»(ûöYø—mPËíü}¿$\^Ö(_íäÄ`ÑsÀQu¿,ü{ÁÜÁc? ÎÜÃ;T¬TÑ>0³3qY¢k&;“å…¬5pjÈä)Ø*¿l*ϘOÆžÁ”íY„+V¬À½÷Þ‹?ü6lÀ×_­¯44`&%‰Š² 3`¹ß½À˜Ê…T¾k™÷“±w€9§uóÂj‡gNÛ·Ÿþðú`@k`Á1ŽJe¢ \=çÊÇþ*ºÀ±™X¢âÈ]G™*Sâ3#uòï¿éݺé?ÄJóæ!xÕ*¿,–Ù&##Cg­èÕ½{wüðøûî»ñì³Ïê« ³³³õ8n+%‰Šª [ÖÅèRÿ§ö³px8ô0+h¢¨¦Üy6Èû'°j ~Ë#e?p:ÏWž´-%Ü}T®š©«b„ŠÝp€j¶ŠU|èY'çöe]Îç‰.Y¶}!K[.ãLß¾(½mÊ-Y‚ð¸8ütÛmÈ©]ÛÛsE˜zæ™gpÓM7aÍš5¨U«–©§Ÿ~ 6Ôpe€ÌHšàE"QQTQÈ`]©ÜWf=,ÿÉœ¥N%ë÷tê+*û%Ï¿Li, ̨»ÁgöZ¦·íUTƒ/[µÑó\?ø<½ì«"E¢k&S*4Yº¯*<'_Y÷܃²›7#læL䦧{K*f¯¾øâ ÔVàÅÇÒÕó³gÏÖ“8Ëð7ÞÀ©S§ôs&&Y,‘HTÔ$'mG~µøYÑÕÜ,`{Ål í°EQOÅ@·Õ@Wdapú¼Ü½^îY†¬·à\9x·Šã*–ªà°7~©úžÇå„4½‹®›ÜýX„¬’4!Eî7j¬ŠŸŽœ³g5dU¨P}ûöÕÛ˜R;vÄ„ ЦMÌ;W?Æ1:ÊŒ!©)ŠD"QQ–O~ÞZCm÷ò]sO‡º¬²TXˆ˜¼šÜw£?î>/;{õœìÏ@©*bU$«ˆ‡Sœ«âw*ÞGÁ€å¾Q$ºê²­ dåßwN÷뇠¼<„O›†R›7ë¾*M”¦OŸ®3Y_~ù%–,Y‚ÐÐPÄ*8KJJÂñãÇuÉÛHK$5 `ùd`Èký0XœüŸ½éfpºðùà3Àþr@­Gá߃^pJ~%]ÁãLX¢ÃdßÂwì¿V±NIr•ŠÇUQq—ŠøK KtÝdÛ7°J—)ƒìÎq&279‚Ê ¤hÝ`·Ù´iúôéƒúõëã‘GÑ¥B>Çuhá`àÊ%%‰Š‚°üeCÖYEAiKÙgàѪTn¨Î7ÇŒžÀw¯#S5ê@׺ŽQõ)pO°otÉBQ41U«x›×M ±û«Š§á” Ç«X çªB;›%¥BÑ5—]*4uCXÒ‡ ѥ +W¢BRκ2Rø¼uëV½=AkÁ‚z~!àCBBtYÐX6H‰P$% `ùËöÖÒY¬¾À÷;¿*ý?¿"¦ 5uõUƒ€Ï£¶qŠ–ÒË+¸úOàÏÿz?êôZÑËÌG<_éÐdÊò<ëpÉò¡ÚžQñ˜ŠŽpì Êh‰DW]¶}ƒ)¢ysdüAýPpöþûºThš× KÔ}W,nVÏ 6LÛ8Œ;Öëìn[5`‰D¢¢"¬så×ð®(*3øÔöÆ ö™—rNÆàH+à/KXõàNE@76^› Œ}h ˜Í"™>-sÅ¡ÚαQ¾—ŠOT¼­¢œù† Utð¬göã×›%¿ü¯¿Îwümp( qN?V™2ÈìÞY-ZèRaèG!73ӛŪZµ*æÏŸÃ‡#11QÏ-œ5k–îŲ‰€–H$*j*yå»(úú»‚)P)õ€ßå*èù+°h›ãÀNÀb&+[UÎGÀžŠ ÄQ•+ÜRh|Ðâ íKàÀÏ{Z5Wq§Š½*êÀÉXíTñ¦çyáÙ§5N™1ÎHÝÛÕµk×—êÔ©£wˆ^BAÆùN¢øþíÏQÐçr›e^èóº÷ÈŸ÷×Ä÷®?p0rÊ—Gð’%(½?2š6EÎM7y3^,¶mÛíÛ·×pFW÷3f`Þ¼y8pà€]¶lY/¼™rda>6"‘¨ðiß¾}ˆ_ç¼Î{L¤0b&¿\Ò/?É`,÷¼Ãì?K/ÂW™žÛ:bíO£ ½Å¹†eÛï&~ü×ðe²Ìë°üø“Ò²žÇ6À)¾˜½Z¦b¸Š=ïés8åCíïþõ(²3¦×Æ=Î^jöÂ~_½ï‚>ýœ)™Ï'»©;Ð>ëŨ ¬¼ˆdFF¢ÄéÓ¨6q"‚ôó¸2ÀD/,:ºS´oØ»w/z÷î}ÎøÉÊŠD¢Â.¬óËÏá}> ¯@kFŽº `ï+/h­NDsƒÕŠëÕA®X øãXàÝy4Ù¢ü™Î¦öUž}±LÈï…­^£UtU±œñêÃ8Ñ*fx+ã>9‚ <0[ÁÌEpp°6¡äÐ_s¥ƒ'è‚ÀëRàãr@åbËvæy‚&ú8õïßÕ«W×pqË-·`Ô¨Qz Œý¹ÌˆfgÂÃõ›ù¡C‡ü`"¾³K‘»é½TåÊHENݺڀ´RB‚öÆ2½X\Wý2Ä·ß~‹¥K—b̘1èÔ©&*ãñܵk—׿!a[$‰.VX–,Ý/¤$9ýR?×>4¥ÍiÕ:¦žøÛpàÅÀµ“ÌŠ@ë(`ú@çûJðÍ+„g;þ´¯­â8ŽîÂÉl±ÿJ½¼ž[H@KñlC+cgGå¤Í×gv‚Y f(Ž;†åË—ã³Ï>ôiÓô‰”AqifÓ¹3ZvìRâr¶½PÅ÷Ç÷J#M^G ‚´´4¬^½Z¿fg¸dPz=1vìØ¡ÅàÁƒ½Ÿ½°ƒ„mÝ@  jÔé½zñ „¨ïùõý›¿Mß… bĈ´íòjùòåqôèQïq±ÿD"‘¨°J벯*äYÓÛØîYšúlŽözgÞö)˜¯ˆi¸¢¯ýЍj5Æ-T÷_u`Ê@_‹æ£ƒáÌ*l Çpto¬ïTLU1]Ee8åÂ]**š2”°®×IÛ¼öøñãñÜsÏé ß_•*Uðæ›oê«ÊÌÀ_ŠKsß6«,¨Üf?æ~Ü h*Knв!€âþù>-Z¤çí02335`ôR`A'>Ï ˜Ñ¢×ƒû衇ðÕW_éÇílM ñåÈ=š•Ó¡Î*ø,uèBÔqʱ>'3y\×ÞžÇã›o¾ÑÒËÍbŠD"Q Ië×åžUh*Ûsß4¿Ù=[v6ë ‡A·ÍQðtX®+Yxf˜¦ÿ¨æd¨ dq¦ÉÛjüƳfµ8º‹gn3ü“O>)ð×ÿõ:A™×eƪƒ:áÚï§qãÆX¹r¥¸0³Ñ A]F#¼ø`9pÆ÷Ã?ì-¯ñ9~f–Y†kÞ¼9’““½Ç 55Õo»””ïs|lòäɨW¯žÎœ˜cw¾ãfßæó\—¦™“&MÒ eÖg#7ýž è™õÍ`cÂ'ˆ˜^.w¯Qa„ ·uCÉš5‘£þ2Kúe±xÜXVeipÙ²eúo`È!xå•W´/ÖŠ+4€]I©X$‰IX'7@™l• Wö:ÆŒƒ­~À†®ÀË»€é¿x<³þ¼ è鸶È2ÆméþÎ =²n‡cçíy_js<Æ$4nä•Y6h]r¡ ì«©[·®&ì«ÃÌhÔÎ;±nÝ:Ìœ9=zôð– YNzòÉ'qòäIôìÙSŸŒM–+FÄ J'NœÐ¥9fÌs¯½ö¦L™¢·cßÓðáÃý2fGŽѯǞ 6\”M*¨GËd¿Ø7”€V­ZaôèÑ$éñäÎxÙ @ï'Ú°ïÈ}õ¡}Ü ›ì†woë©§©Ž ³Xaê8åeeéãËY„;wF¿~ýô@h–Y Züî¸Ýš5kô•…îÐ…õ؈D¢â-¹úÒäZÚ³Ýë1Ìg^5XÚe!•›D¶”SÐÄ™†Ç€ÏÔcÿý<°>HË÷ì'TÅP÷©øθ‚V’Š8uRúS“&MÐ¥K %íÚµÓ',Q(YÒj®ö¥ïx‚dƒ7{”7æ=˜‘YeCÅ4Œ—Êr}~&6És?¬ÿgïJ€£ª¶í‚ !H€B*  €* –ðŸúTâS?…`ÉûO@ ‘ÇøXo;ÿ"êVñnóz-°ða`Ýý†d%=ÌrËß Ùºx* øbgÉ*M£ùe?†?*é ÏV:¯šåm3¡$àþÑG¡S§Nž: œ”LRBÎÑ:ÿüó±a䤤xŸÉ ø“O>A¯^½¼sà¹3—ÉUЏPâù“\q[þ[!:ƒS éÛ·¯Ý†Š®#¢Á¥ I¨'ä˜|%D-‘ŠF¹Gr.æs“®y?îäBR@µŽê ¿¹&ù“\’´¹.Ùu?+œ „[UÈû˜×¥ ò:t@ C<ë½ó敆‡'L˜`é ¿Ç®]»ÚŽ[’N‚KÌ …"\ !Â3 ×êAò·Ä;+w °žžY«€ñfƒ†5µ¸˜¸ rÐô„s.¬&dül8*$ÉLíÚµ-y ÒËä¹Lg+ìB×n–ä» Úóì³Ï¼L]ãÄZ§N:tÈK.ç¿åjÕªe“åW®\iC„ !Ê:nGŒ÷ƒ ÉT³Ù/%ˆÏ’?4H¥ëàÁƒ^Þ•Lü‰#ßâJbÁ2ž«Ÿ¹IõòBΦ²x¦áOxNH@^Zš­(Œÿâ ŒíÝÛV_R½ã}à¸$¹boÂçž{;w°Â(«à@¡P(ÂJ°Î<\ËÍ­²yYô̺xm.0L<³ÎîŸd¼^RMȰbUü‘O›ÿð;Jáí¬ÃPÚûï¿o“»™ßríµ×ZU€¹Y¬nóçéÜ,N¶´dŠ•b$7´51bÒÓÓ½smEý DÕ¡ôé§ŸÚódŽ×$`”r.Õ*"T­„D1±~Ó¦MöïùóçãöÛo÷¦ýBJIŽWE"x^ 2'Œû0W‹‰ôr¾Ì£b»¶á9³Jd –ë@îæ%‰7)D+à÷Æ*4¤‰…Q añb—Ž=nGÕ’D¸uëÖj+ _yåû€I-† EåCdü²‡>Ü¡›o•,óÇá>†\•ᙕֱ$žáAÚ3ЦáI³,E‰’•DrE;+*Ì?¢rÄ¿YE»VÙù-ΔE€L˜Íš5³D„ ¡;ï¼Óžç7Þàs$ʇ,!$c¬0äqH`zè!ïØ¬âc¸‰Õ€$r 7É~<ð€M>§èÔ©Smn”ä¤Éñ…n‹Ï™Ä”Š ¯y ¹O#GŽÄÒ¥Kmnß:t°•‹LÂwÃ~®}A°Å. w¸DÉ’GCRsXQhÞKøøcÔÈÊò¶«W¯:vìh¿’ã+VØïûŠ+®°Eþ" %X …"Üþ¿êá|L鼪j¸ÙÀ·†š7›i¥`'ðöSÀ K”+fO@I’û³\× Aƒ¸ûï¿íÛ··^KL¦•€ ’æ8‘tpâ¢â#ëÎD¨J&F)Ï'±“ÐdÀp>Ï͉"¸kiàn+¹e|õ›Rr®[·ZÑ]Ç}¨"Éq¹?•%WQ’¤m¿ñ©#X ¼Ê=•d6+]„й÷=R ÷Hºùk×"¡woDoÙ‚fŒî¸ç/Û2lȇ€§¥¥}5…˜ò;â«{ß"é~)ŠÐ&¹‡?ÜÊC7|h®ßÌBϬ½Á @—Àÿ<´4ÌêåÑÀO‡KÈ¿ôÇÍ2~Ò¤IßóÉŸ•X|¥ªã>õ3”ERECu‡ÕxT»„¤HXçt%À»J†«¹$Ë%—`ÜWÎÏ=¶»N>GÈŽ¨'ò¾Ü÷|øÊsEKÈ’[ à?¶_q÷“õr]nŽב$œIBJð÷U›5Cnˆþyœ³d výõ¯8k·å}¡«ûôéÓm–ÜWi¯ãÞO×Ú#Òî™B¡ˆL(Áúó@BåÚ=xiÑ3ëCàÁ  os ?=³çòõ½À‡+JµÝW&´† ZÕ€'v¾Ç$oæf½ùæ›¶M ½˜V­Z…Ù³g[ÿ!:h Ñ’ÉÿTU?q‰Š wòt­9×WÊÍ’óó‡‘Üó÷‡?ý6B¦Ü˾îD.ç!Çó –#ä^»Ƕ‘)ýlw]¤"€\³¢ðŽ;PÃŒÁj™™¨ùŸÿ ?!ÁÛvìØ±^¸š– 4!]³f êÖ­k=Ì2í.‘|ÿ Ed@kŸC~;ûºÈívÀúd I5³4®ê$Õ6}ìçÎiiiÿÛ¤IZyã7lõ“´™‹5hÐ ôîÝW]u•­´£‚Å|"Vø5ÊNþT´þ‰ëT‰–¼ºê‘›å*YþÐY°W÷î:Wò¿ºŸì®Yf°ëu×ûI¨W©r·õ‡—¼îäÁ=Æ¥-Ãúõ¨¶|9ŠëÕÃÁöíU.•{ļ+šÊ2W~X|o̘1ÖÌ•~âî÷H¡P„X}þꫯ¾ƒ’ühé7ÌÂ4 žP2¨&¹ÿùpàýU†¹»ƒ×Ÿ†gïqC¶z=Lzø¯Ú@Œ<Ñ3äBeŠ!AVà1ù›•mLÊ2dˆÍÏ¢:óŠhðÉdszR1?«¬þx'›\,Lè_ü„ÆO:üêSÀMó­sÉ\°ó¶¯_ñ[*¸y]å]«;ÿ±Ý~‰þålœmØ6ÐÝý/ÁQó×þòKDïÛ`YÁ?ø³r“,`˜8q¢Í‡~¿Ã»B¡P„24D:pÕ«cÌIÇë¿þù<ðsàÞê@‹îÀ˜¥À¿–6É%iau*óéŸàD&mc|ðÁ’2“=›Þ{ï="¤•'0Ú°lžû¸‰ÅÄÉ(nÞL°þ~2É–Õ0àæ8!¸cn\äù`ë*ªÎ¹‰ñþÉüxDÏ¿»mYʘûwY*Y8ÂßB§ m['%!Æû ‡ ybÍ|+*¨ÇI>ÃÛô£ †ß|Tò •d)ŠP†¬ÐÃQ”Ýj§Ø<Ëõ–}<8èŸ ôn´jUBó¤¿gÈîÙUK{Ýqbcù;³,^Â+T®˜LLÏÑ£G[¥€JÖ 7Ü`{éq{†i’¨~ª•onŽéÎ;dˆ!_+;xØ7Qì ˆH¨4ô”¬š5‘o|µE‹Pý§Ÿºä"ɱ@|öx¤'ó°®¾újŒ7™™™ÖíÝU;]e1œï‹B¡ˆ|hVè Š1)óéÞž3Ø|5ðÔgÀ˜ÉɈ6$%ññÇ‘`&&üö›÷ÄÏIˆmeÄWhëÖ­xÜldžº|Ÿ‰ï/¾ø¢u‚g21±mÛ6–an›t*Æ®?’+E XEÇ•ñ ç|,^Q‡(2c5&+ ±Û·{9g\O••U®$ü]ºt±ê*ß#Ù w’©P(*'”`…6\ûI€øœmÀ¿:¯»ŽFS¨3{6ˆ˜%KPhH’$jK艓7í¾ûî;kÙ@ß,š”2 ~Ïž=¶š‹&¥$V¬¨`?C¾/ Ù'ÓÏPò¬¸?[¤(¹ †s©ä¹•Ö>ጀ꿔¶l‰ªæ:ãÍøtC~¬‚e÷†¨Ùë1##]t‘V*а…¬ð€—‡…@5ËVæ™É){Ü8ü>hŠPmõj44¤«Ö¬Y(ܽ;Àéœ=õØÒ…Éð IqÂêß¿¿õ¢W󴨞°2É+Û´ic[ÞœL•¡’«Šƒä×%W‘Ò‡Ï òDÄýûß8š—06¹ Ç¥¿êÔ5€U‚¥P(ÂJ°ÂeÙ9ä1䛘ˆ}÷݇mæÉ?¯m[DíÝ‹úãÇ£>+×® ˜´ úa1륗^²U\ O1ÿ‡˜2eŠMŠg@¶øê«¯lï??ÃòÂWJ®N ’4råªPE¥žk iW1˵k ¹$±ÏÊʲU¯¬*dÂ;›m»þa …BP‚^F²òú«Y³&jÆÇ£°S'K²ößr ëÚQkáB$1d¸`ŽääxÄ(99Ùz`QÅbB1 ûõëgï²u ÍI6d^›ÿfŽ =³8–çI¤äêÄá¿§‘B&\ˆâ–-q4.1Û·#Æz7¯ö"tq'Ñë­·lŽ 18³³³O9P¡P(Î&´Š0<ÏäuªX2‰åŸwv>þ8r.¿‰“'#vÝ:$¥§ã@Ÿ>Ø?`ª$%ÙíêÔ©ƒGy$ ‘ñ7ß|ƒV­ZY-V2?«oß¾ÖÊNñÒ”Ùäü]J®NÁZïDìIMµ~XQ›7£ú–-8Ь™GšhÍ@û[¬]»ÖvH5Û_nÆñÆ­9®ß#L«  E¨B¬ð…gßÀI‡*I §ê 8œ–†mÏ<ƒœ+¯DÕÜ\Ô™>‰Ã‡£Ê?àHAç'äæ»P5 ''­K/½sçÎÅòåË1þ|ëïw÷ƒ*¹:yD"©xùS†Ô5i‹EÌÌ€DwŽ_&ùsüP1/ +U->D¸Õ¬‘|¯ Ed@ VxÃ,)ƒ%KHV͸8_q²22°ûÞ{QÌ÷—,Aò}÷!Χ¢C‡<+’+†fºvíjñÍKÍ„ÆJBÚ:¼þúëvÂó>8ˆÊ"WJ®.ú5šqYܸ±}?z÷nû*„©{÷îV9åXûùçŸmþÕ¼yóРA«ª–åî¯P(¡%XÏ?ªY$K$9\bSR°gØ0lÿç?Qд©ç™Uwüxë™å&“\Í™3Ç+†fî¾ûn|ðÁh×®]ІÉnò±ø\)¹Rƒ¿ ɸárË-·Øþ˜ ,ÀرcmH:-- ¯¼òŠ}xð[5hhP¡P„24+BàŸx‚õ¶ËëÙ[/¸‰Ï<ƒZ‹YϬê?þˆÝ#G¢ cGT)Íã¢ûûäÉ“­š ¡CQ¹„ÀÉ1 Q³”\)ÊCy½$ÙQ€æ· ¤ëÇj× P(ª`EÜɈOýT²¨JÙ!'+C°\ϬêÇñÌŠ·ûº9ZÒZ|‰%WŠòàÚ5Ÿwž}/fëVT)(ØÆUb9Ö¸ÐsáßJ² E¸@ V¢Üa9žY$K$Mþäy.<ŽLt2Á‘”)¹RTGÍø#¢÷ìAÕR2Oȸu‰< .–.]ªÄJ¡P„4D¡ð7geKˆ—|zf¥¤ þÔ©¨ýñÇÖ3+vãFìþÇ?ß­¢JC†Ü_öqÉ•U#J«¿”\)*;nví²³è 0O¥ïMo™ÔÎ1g·£}Ã]wÝe½ÚØ›Pª_Õ¢A¡P„2”`E8ü}Üüd+˜gVƒáñ¿O0… z¹Vþ/±d ’JE+å!jÃûz¤ysÅÆÚ!ú^-Y²3fÌÀÞ½{-ábL¾O%kË–-VÉêÈ\Ag +ÉR(¡ %X•2IøÅ¯få›…žYfÂKÌÈ@Íï¿GÂô騶f ö>ð Úµ tãvÉ×RKQQxžiN‘DRRžxâ k.*ïqlm0dŒö lPÎ1Gâ%ŠjYF· …B P‚UIàºyZ^ȰÔ3+aæL$Ìžm=³¨hí:ù·ÝfM"¢j‰‚¥PT–\•Ž©äXdåê­·Þð0À¿[´hóJ“âý$J}° E(C V%C°¡«N”zfå>§LAì¦M¨ÿØc8ô¯á`z:ŠÌdGeJAEA¡¨(ª:„¨ÌLûwÁ¹ç–¼çŒ?±q+T]•JªYÝv9ª^)ŠP„¬Jˆ“ñÌŠŸ7±fbÜ7z4r;uBLi¼*XŠŠÀsþÏÊBÔÆæ—'ùÍ›ÛuÁÔT×cM^ýÛ)¹R(¡ µi¨Ä¨¨gÖÎQ£¬gVµÕ«Qð`Ôxúiäeg#77×–Ñ+%K6 Êþý(>çä5jäåS¹¶"®çšø_É«za)Šp*X•åV&&â@Ÿ>ÈoÑI“&YcÒ:“'#fÍìNOG~Ó¦ö%(Bn˜/êÛoWFþÅ£ ~ýcT)1±õ·aøCÛ …BªP‚¥¨¸gV“&¨;cê¼ýv‰gVf&² BìŸ}Ї%X;v úÓOí¿^=ЍF ʸ;”\…7ü ú}*"J°ÊR³<’Õ´)~9y­[£>=³6mBÊ£b’Ù·êÎ(NJú³/A‚ðò¯–-³ îÅ È1cˆpóþÜE'ÜÈ„7p¬2龺8›cAÎét~æ‰^o(ãLÜŸH†æ`)à+›æeU7“#=³¶N™‚ƒ:¡jn.›ýjßsbþÑÒy…™P‹óòõÎ;6<˜Ó­rRS:h^UdC|ÍdaqŒ‘÷ùê›Òí]bVÑÏ;‘ýÝ0¶»Ïé¸nÿµ»ÇöÞé²q¯étëtÞŸH‡,Å1ð+WÇ$ÀÇÅáh»vÈ?Ù†Xåš}b–/Gí¿ÿ5fÎD•ÜÜ?û!ï‡ù»ï½p!Žšñ³ï¶ÛP\J¨$¡ÝŸw¥ˆÈx÷ÝwqÍ5× Á<¤ñÁ-%%·ß~;–-[fí^¸`9rĶI*((ð—K>ÊšØÝõëׯÇóÏ?”¼[~ÿýwkvë’¼S!.¹é¦›ìONNÆ¡C‡¼ëä:žçÔ©Sƒ^gEŽïßV®%11Ñû|÷õDHWY÷çTïMe‚,E™Ö4Úmüc~0v „þfÛ¢æÍm˜°Öc!~èP¯Š¢òB~œ‹ ᎞1U@þå—ãpË–^3q!Wª`E&d <ýôÓv5j”uçß·o¾ýö[K°ÒÓÓñùçŸ[bEò±fÍk.+=*]…«,åÇ}ŸÛŽ1Â> ºÄ-Ø>²={`¶iÓÆÛ^–òÈDY •´ãµ.7ŸÙÙÙ˜7ožã¼N®ãñGŽyÌyúU¼ã}N°Ï­[·.vìØq ¹ò¸²þŒd®^½mÛ¶ z~J²Ê†æ`)Ž‹`ðîÂÿ\o™í¦™ 4nÌÄ.^Œj~ˆ¨uëpøá‡QÐ¥ PN²"2a´Íq•Y³5>Ž‚¾ï®»PH5À³b’¥ä*2Áq0a¬\¹Ò’ Nдw‰G·nÝP»vmûì³0dÈð£ý¨ÐŸóÚk¯Å2ålX¢Q¤élMÂÙ¾uG*Ç kÎ8ûqèôì³aÛìáØåO Ù·µ¹› ¾F¼¸ª¸úêÐ!{p“–á“Ë. «¾õ­xŒYA}fv‰«Ö‰ ÀÄ^þùQ0xã:càöÏ»;½zõ ã²gç!ZÎÈž%X©&Nœ]мî5ÊûSöl±•%æÎößÿ‚õ ËÙ„ Âïÿûhõá:ò}3fÌ(ˆÄÁÎ:ë¬øLã8RLO“•cqS&²î½÷ÞгgÏ(ö(±rÌ1Ç„|0O=(Q´óÎ;× Ø÷nLêIÙ¼¿Ï>ûÄ~ñbiìØ±Ñ¢ÄµxAvß}÷EëÇÃFŸpM«'mÁÚÄÿ´ý¡‡ ·ÜrK¡íÇm·ãoøÃb`<¯±ºa±¢ ÖÊ$..µ\úþæ£,ÑhÒ â*èÚ:Žg .Í>÷åÙ/m‹g±Ôü•{°uãó=}öÙáÔSO–’Gy$<ÿüóáÜsÏ ?øÁ¢hDV£™3g†+®¸"º»1 òÜ#ãÇ®8‹¢\„V$s="È6!€{ ·÷Ÿ^aã˜eË–E15xðàBXœzôèïSømÏ=fD:´`iîe\~v<íøVö£‚28.9¤ž¸üì9Š«• ¿råÊèºC Ñ^ñq–aB—3üL¼ÑÀ¥Ê9·Ýv[ìßtÍØ7ß|³pÙ³gGËŸç PqAš^^âÁgÄñ¥bàD]ÔSb“©/(ycö X}Î9¡2ûÅU=`@h—ýÚ*û_9³Z~ö–«0ztè}ΰü¼ó§ÿþïaCí bñ{&®üÂ΢uc®á£Ž:*ŒÊø”)SbàûyÙ=b¢V¬M¸Æ^|ñÅ‚ËÍâ³°Ú'…U‡¿lÜK632÷ÜsÏ‚;nÒ¤IÑRd×°ºØ†Ð•‡PîG„Aé—â`Þ¼yÑÕfB‡ ‘†°±ïmÁÕi×Ks¾½òÊ+QÚû}²£¸ íš¿ãÊCPÙìÊêÃ9•••¡{÷îñê‚Å ¡f}am÷Ö3ßöE‹E×&Â!ŠëËÚ~ûíWp1Z™¾ï|ŠâèÉ&¾^²/`uÿþ¡òî»ÃêLXmìÒE9³Z~ŠwMö‹¼â¢‹B§k® íÖ® •™¸þäÇ?üv¶ÁqÅf¿ä•š¡õƒ•Å>c/2¸®¼òÊhѲà÷ùóçGWñPÄ\äã¶È#…(ÀÃFLB`"‚2¼°yçwbœ–ÏBîW  âŸü2MDZÞ,;S?ƒ«[¿~ýê,\uàó Ú=O= l·ú(Û¨3åá µvá:Å5hå±S†€²kÒÔÛúËnE‚érh¸JGަM›'ü/Cö½DpZ´ãÿÕ¦V±2<úîGKlp ®È~µV­œYM@šYyKœz«ÕúlPØ0eJèx晡ㆠÛn–e'ëT®ËQÀ<´M\a½²Ø+¹[7Ü'b››ÉîüP!xÚî'Ä.ÀjCpNž<¹ °ZqŽYhØn¿ýö¨Íÿ«V­ |ðAœ-hba.EÀÂE\“•‰HCyˆ¨ 樘û÷!–6ÿC à޳}”KyÖ+ꉕŒX3°ýÛm·]<þ7¿ùMÜ€~¡þˆ'\¥Öl=öX J7è?Ë!Öv{FXÛ ¬U'tRÁÕIß!¶°¦™(³v¤Ö/ý0ª ,±åÈÕµÙ¨rìØŸ}ëcάmÏ??þ Iœ€ø’¼¥*jx("nj…ΖYu®Ï/ÜìáÛîòËCÇÿøP±`AX¿ûîáãÛn Ÿ~z®¸Jc¯ô€n½ØýÈ BÑÉs…E °Ô8=bĈpÝu׎І82w2‚…x'ËúÿÃþ0¦)àþCl0£A€ÛûŠyX–¸7¹÷)p}™kïg?ûYœygß,Cˆ<0„Û}yë³épqšu‰¬ñ@=€ãh Â-]o“÷°,QOêHÜ™•}â‰'¢à0`@¡_NÄ‘!⫈;þ'N‹ìøVO®‰õÎĵ°˜ù¶³aA#0p¸k){·Ýv+ÔEL–ï }w†–ØâäåÌÚæ’K”3+‡TXÅ©ÕÙCµæþ'„K/ 5ýkh|Þœ¦YuÜ€µnƒõï¾6Ž:žrJè˜ *²´¯É~/¾ñư¬_¿‚[ÐÄ9Øe¹j[œ’Ý#–› ×®0bzÈ9Å`衇"+•M†ÀRıX^ØwÑEÅû·³þp¥!¸¸Ç¸§vÏ>9µ8‡€oö]}õÕ1U¢á /Œ¢Qbß›uçÝx?•'ŽØ®¹æšCÅ1¸Ïp[¸oik8ÁbV0o½bã¬KÔ Ñie“…›Žò½KE¾0f9’‚~ÄuJÜ”AˆE_oRM”j;³)ƒ86>#RW üpÅšåÏÄÜ¥i?è;\õNù“ag[—éÓ§/?ì°Ã¶èÅm°ç×fí%‹7¾ìKÞiæÌÐõæ›CÇ—_þ"ÅC6H¯Ê„Cu6H·%vȦš“´5ËøKÀ,‡evÞ¸tiÏ<Ú?úhh?kVh— +îº+T\˜¡dòÍ}ø¥Y£ ®È>í<´¿ÿþОÜfÙµª³Á¢2ûE¿ìØcÃÚLDY"QH[^) l×ùõc³Ôl³ÌìþG@ú×&<ðlñ³”íþãµ-¡ãIc‹ì?‰ÂfÀ¥AÚéûvŒ¿¦Å Ú¹öüÕ—i=-Çbά «›eqgC,"¦žv-ÊùÝï~ƒê rçœÔ’äÛnm±síZym·ú®­µ„[›m¿¹ó­\?ÒÏn-0c3ëcr€dÛðQ¶1-³*ÛÖp[òÑ7¦<¥iÍ‚êðÃCMöë±ë-·„.ÙÀÝiÚ´¸ÌΪ‘#Úì—op‰LÛ u⛈É~•¶ÿë_cN©öÙ¯íP‡Q“‰²ªì×þ†U«¢€LÜØkÚ_?XÄñóÏC»yóB»ÿþïÐ!Û¢°"Ùbö«–Y‚•‡Öl³Má{{· –Äi›ØÀo¢#o¹/Fü_/ì;aâÄ–±IËð¢¦T*ÿ=ñKंÁ–·>Ù5- O šŠ/°Ò{ß×™8)܆we?˜ðOËÁe‰û1Ïeéƒó}[ürfÅ>{Ÿï§µÃ×ÑOF41°¾Ç¥‘ÀÍNÍÎ;ÇœYÕûڿÿ~Ì™Õñ¥—bÎ,Þo xaµ¡²2´ËÚßñÉ'C§©Sc6ô:Çf¿,–e}Ó9X6XØ0o¶O±¥-RAÿ'ŸÎ‚!Ì™ó…¨z啸ÜM`@áó:þø°4{à¯Ùa‡/—ÚAÏ‹+³`iÆ`Û$f á^0A’w˜°)&°Ò‰©ððÇ^Ü¥×äozM_/Žü=ÌýíãÓ2½ ÌK¨k¯Y¦—!‰Eñxk瑞7žzÅ6«·ï;¿v`Úç&óúÔ[©Š EQ ,Ñ" gÖš³Ï5{íîøüó¡ËƒF‹ ‹FWtPLùКaa䎟¶›7/l?yrèš ¬(jrøøä“Ã;„Èf?ŸÑ›øëôqލŠVnÞ·Þ Ï=ÚO›*^½p}²±¯:âˆ#ÂÊ=÷ k²Á –æ PT^XéoÛ%µ ¥‹›•æß³×Åî_+7½¿êXiýòÜ]y1GÞ‚å-t¾éñéýobøŽq½ðãªöûë­R¤0·dšf"µÞ¥m/¶¬MZ¿ôs±6zK—b°‡–hQ{Eά­î¹'lõÀ16‹œY«/¼0¬þñÃÆ­·nî*~ ®Dœõ:5ì:kVè¶hQÉ$¬Ÿ÷ïþq a}ö0îš,áágúÁ þåáYUõÅrE™˜Ú¸dI¨X¸0´Ÿ;7Tüïÿ†Š÷ßÿb’Am| V²êï~7¬<ôÐP9hPXA.œÚ1U/¬ÒÍ„•ÚEêúK{?P—L\\âCÞ¹y÷]1‘•WFêjôuõB¤˜ÀJë––m+øº¥â)uûùvWvLÚî´Žyï{ÁêËÉ‹ÝÒwº~$°D‹ƒœY+¯¸"¬ßgŸÐíÆcž¬n×_:Ì›V^vYÌ£Õ@Ìtš>=tž81<“½þ—LPÖ.¹WO9%Te·.µ®Áv<¤1ñLL¢ÂÕ«CÅÒ¥1‰k9Æ*+CÅk¯Å™~o¾™²&T|øaŒå"»þ•Éø¬o¶ÿþaÝµ½z…µÿú¯aEïÞ¡ºk×`æ8³¢V<ù¿}àk*¬ô n=¤AéyƒmÞ1éqyƒ}±û$½VcëZªnyäÕ·˜k¯TŒS©×>Ž,µ y¡U,fË¿nˆ5©¾™ÅÅX1±(†–h™°È*khë­¡óäÉ1W¡r̘è²*Kˆ‡xãÐéé§c{:,\-JxzEvìw'L<˜é&Äì¯ýË£¯ÝŠ¡âÓO£û®ÝÊ•_­B·nacÖ¿¬¹a«­Bu&XWõíVfÛÚLÀÕdûÒ_³íÝâÞ^Lù-±sEëÀÏ&5òà†¸ïŠýïËðeùãê»§ò\]ÅDV}B¯Ôµ6Ç’ã…™ï³hå¹óú3ϽZª® IáRŸ¸ GK´hÈ™UõŸÿÖï½w\Çp-ëÚÕ®½UްLP7B&-Å&ä«êPU¶yûíø»ðež•ôˆ{Y†31´.P¶Þ:¬íÝ;Ôdâjí.»„š.]Bu&RkøMj+‡u_qS˜¸òb*µV)6£õÂÀLœ‹rÈ!áéì¤.`¦û“”’Ô$½„R÷F1qÅÆ"Æ$ÂüðÃëÄ1;8‡X¶¼NþóŸÃoûÛðꫯÆ<[äÖºä’Kê¤aø:ÜÚi ™µìé~öžßÈ‘En,ú˜i8uêÔpÁÔ)3lÅH-n–©Ï“–y™;wnèÕ«W|QÀú€¬qÇÎäzb=<‚_Þ©ªª*º¨XÁ€òçÌ™× äzvŽÁ·ýöÛÊAÄYFtÊB”a=óû¼˜ÀRÃ2;>I)"wO“àsB±±¬ÏÎ;ïïKFQ'kã±Ç¥f©®Ïì¿÷Þ{£˜ã»…å k”G]i‚”W¸VÇW§î¸.±¸ñAËÑ&Ê(QK¿ÑX»¬OªÝìbþRîP¾ÓÔ—#Çðš2MÈR.BóÑG­óù`ä8ÛwÌ1ÇÔi/Kë°÷O~ò“¸‹vÛçã—ñÚ’‹Ò77XB47™@aM†î²Køû)§„©¬s–=(—öé6d¢&¥"{îý_ÿ¶ÿç? ¿xyð›Èò‚ɶTHå *;?/IhÄ.QÕ6ð"ƒ5ûˆT‰Û±“mñâÅáá‡GqD˜={vt%Ú20d g?KÀ Ì<ðÀh…ñåŒ3ΈËÀ° ÷Í7ß-+¸9†ÁŸ…žY aBY-Ê1±ÁF¹v*¬lC<ð]³îŒ?>®óç­gþœ &D—"‹J/]º4 2$.^ÍumPêPš5kV†|GX6°!¬Xêæâ‹/.(Ö $k;ß1‰>óÌ3qí@aƒCpò?ÙÜRˆ#®‹x±>AüÒ'ˆØ´oŸ|òÉXÖsäs¢¬9ÈûœãËdDzö Ï†%þÎ^ûöR.}vÚi§ÅºPÏôói«"KKˆBLw@ÂÕv ïyd˜sÕUaîu×…÷N8!¬Î~ûسNË–…½î¼3tËÆ^dÙÒ4&˜¼pò›_ÆÆÄ”¹{Òt J¹ L`aqé“ K|iƒæèÑ££õ„ãž{î¹h‘á=@æÿ²{˜{‡ö裎nFDkp’½œEŒ¹×ðe\KÇ º°à ÄÌmÇÂÇœ‹Ð0‹ç ÊL`©kÜ6sùÅ•Óõ7 X爎O<1Š<\ilˆ¬;üãã÷ú dn7Þxcü!CYÆ 3gÎ,XЍ+ VÓ¾o?¬@ôeØ1X¶8‡ºb}³óÿò—¿úÄâ°~Ö'lXék,p”ÏqVÞ'ÎÍ—‰EŒ´YÚ×{ï½Eÿ³/¯½Ä¶Y]ì~I?oUk+(Kˆ‰Ö6ÛlEÚu=z„·úö ‹>ù$|cþüðíéÓC÷ìoûU«B··Þ =²_½Ÿd?8,B}±.¥b%¢„‡ÁË ›ÃàûØcÅ× –X¥°î\yå•q@çDT0˜"Î=÷ÜBP¶Ý£ ÐfÍ@ˆ`‰A Ù>Ü`-¾ œ‹ a`ó”…`àÚ¶1âè9'§J³·?ñÄq6Þ˜1c¢hLgáÙk¬Kï¾ûnŽ\ÿÅ_Œ¢Çê‚5gÀ€Ñ-fuA|àŠK³ÉcÝ¡ÜeÙ$ê;xðàÂÂÌÜxü衜ªÚÉ/´‡kq.ýb`1>|x<ÖbÂ|ŸðáK=ìk/®›–ÉkÄ”Ï&Ï>úÇ[¯†¸$í:=ôPt Úgèëbí³%’|®¯ÖŽ–-@X‘,FªS­{ÔºîÝÃò]w Ë;,t]´(ô˜5+|#{ÐWÔ>à X*ër[x¸‰¦KРď e÷ e#¿ýöÛ£Ë HÍ@LŽYæg?öÝwß:‚gùòåQ¨™ ËÌÝwßgË×ÊBä˜uÄc‹-[üçøø*È úÆ}‡»Žµÿ°¨™H-µˆ‹“O>9^ë3±Þí·ß~qA_ôïß¿à^¤ ‚ü–~v`*´è¾çX…8Ñi}ˆ ÚcíÃG ™‰ú–×'Ö—ˆHâ߬®iâRÊĺh}ÃçL[¼wm7ë¢)m/uÁêXª.väå)k­H` ÑBðn>,fÅâAdæùud[Ï~Ù¿ß·oø¸²2t¬µ›!ØÚ`âëÅ{â…ìy¥† fî1ÄbW˜ ¾Ä@÷VÜ^ð̘1#ôë×/îcÐ儱ý0`à'Èî_®‡°±ÁÚßß&8ˆ ó¥XšDÇ/ùËè¾$fÈ‹«4ΑtÙe—E· ¹Ì´G™µŠ6cÑò®/öáR´}ö´: Zúfßaÿ£ˆöY›9ÅkŒˆÕK/½´P}Âu¼UÏÚlCÞÇhâ&]ÚgÁ‚1õƒíãšöÙØu‰©£Í&°”¸a}?S¬|6{3M!ÑÖb¯ Å` ÑB°‡ŸÍ Ä]ÈÀï}ÜÝ»w³¬àþ%Ûºîºkè´Ë.ñ8› ßdŒB4x/À}… `ÀýÛßþFŒQa£OpZP9õ þÉÚéëAlV3bä¬îœÇ¬GëⱦL™cáL,"}{)‹÷ÊÅ>ßÏmIdI` ÑBð¸Ke)l& ‰-¬lüÏ~ޱ šå'š\Gf]áã2»[<ð.Â=jc9™ÇÍúAlàN²öûßÿ~ŒáAD_ k åš ã~&F‹[”ÁàM:„åØZ˜X…L äÍv%[9Aà¸#~àOóÀ™È!=Áý÷ß_™X´&Ä¡yË"Ñ_—¸'f–'&\uÕUu,‚fé3…%}VŽõ% ®øE¹>Ç[ŸP&Ö5êi}b3€é[˺ÏìF_Ä“/“kâEtb̬u;óÌ3ãg’Ö…ÏßO ikf$°„hA¤3Ú»\W6;0M½À¾Î% ±)xKƒ¥?0áD<3ĈOò³ò ˆ›‰ŠK ÅQ†{ ×÷ª•Eî,ò^!f&ƒ Š‚åÿÖ&¦Ü¡C‡F1D:âqÁ}oß®C½¬\ï*§-X®ˆÒ &°ÄP^±¤¹XÛÈeűÄlk†(Á%få#^ ]{íµ1Î !Gn(®}ä‘G„¦ÍÈô1“”ƒ ²}ˆ0D&¯IAP9nZ,EìCüPñ`Åú„´Xë„ä˲zpû(“z°$í!ÎÏ•~!U®_Þ÷1S¾½&šèÚ†#àŸº0{Ñ×¥-&%n;-m} މ¡ë2}úôå‡vؽ¸eæ—–”%‹7w”5;d 6Ü<¼púÙ„#‘N!7»Ä…õáï3sû`0áåc— ²÷,Ö*/ë¹Mò.5s¿¥KäøcìšéÄ;Çr¸Yùfý²V';Ö~ÈØš„„o9§Ò\N`–"»†ÕÕÚgñQVW_gë§t9ïRµ¾ó¯-VÍú¶TŸø¾-¶¤•áŸ~f¢>s¼Ï>om±û£ÎBñÙ1i˜–je'>pàÀ̦`Ú,é —eÓ9Y–€ŽnTŽ ¹ ÑÂñ¿ü|ƒ(—š1(Ħ. l |ÛÀkÓîSë¿7Ó`gðËÌØ îß³™ià­$öÚ ïR·AÛþ,Éi.©Tp°ßçÞ²k¦çøv§‹l¨…±)ÚPж(¤Š¡[¨_^1Ñ|H` !„(Kl9šãŽ;.}ôÑáí·ßï½÷^8ðÀÃõ×_ßc[¸paŒºï¾ûââÓ²ï}ï{qácA©“N:)ôë×/®·ÇÆš…X¬6ö#¦fÏžPÆÅ2W?þx;Ÿ~úiJ,,MÙl\û›ßüfX¼xq¡[ka„:á„ÂQGSf-?ß[ªˆrXÛ¶ÒÎ[n¹%\rÉ%…6ø¥|$²š ,!„e‡‰ˆ{î¹'ôìÙ3œvÚi…uô°2±Ø0¢ ñ‚ÀBà`ÁÂòƒ9ýôÓÃĉãû÷ØcÅ÷Î:묂»‘ôðÇիWÇc>üðÃh‰ºë®»â"ëœËvÓM7EÑÅ5;ˆ%®ÉylsçÎ ûï¿ÁzÅõYð™…±Ù÷ÀDë׉'žÛFQ´Á® b?–-„å`é¢^¶™È’Àj(K!DY‚µËÑСC n4 ã|x1bDt r.e 6,ì»ï¾a†€9rdAÜ!°öÜsÏ:m0k–­÷hm°ú!Úz÷î]g?Ò<|ç;ß‘•ª…¢,!„eK=bü‘·ÚÜqÇÑb„!V ÇøœSÄ\ŒnǵlÙ²B@9çÝ~ûía„ …zˆœvÚ©ÎÂÎX¾ˆ2%¢gÚ´i¡OŸ>ñ5Â}œœƒÀ"þÊêLLØÙ1ÖaÄ`QGÀzņU«W¯^JÍÐB‘ÀBQ¶naÊ”)·ÝwÞ÷ÄŽ0aÖßñÇ÷c)Bh!^H¯pÄGÄc&”C°9ç ®Æ…åz˜(\„¸äW¶[5~üøXBŽ4\ƒ4¼O`<®HûÙ‡Ër=öˆçðzðàÁáé§Ÿ.´ŒïÖ«×F¤ùk#°¸N^^-ÑüH` !„([F^yå•(XˆÂÊôÈ#\mX‹8à€( Z¸î'• ŽÅ­‡¸!Š@vÜ…¾wîÜ9ƒÅ±†Àâ<^³ôèÑaìØ±1Øü¿øEŒõBPUUUÅã°0O+,dì³ V^݈X½pZu`צ,«/uD`™EË‹,‰­æG½_¾ Žy‚t™>}úrÛmIxÙ/2â–,^ÜÜýQÖìУGÌ¥C’D‚dIrHL y–Z Vˆ¶†ÏÜn.=‹ÁJ³º“Kê ƒ ‡zhÜg¢¦˜¡,(n"ÌDŒÅdñ½´€tÊåúfò¹¨Iv¬g׿µY£Àf+¦m5A¾ þú¼¶kYûôÜhÌ8pàÙ¿K³í£l[–mUÙ¶&Û˜±°¡1å)È]!DYáEˆ‰›ígqV&.Þ|ó͘#ËŠV^ˆ°Ù¹^ Ù{^™À1¼à²€x?¸ó®é_ç-³ã×´:ð¿ ,/žìúiÙ¢y‘ÀBQ–x‘ñI6m{ùå—cp¸ 4^\y‘Ãqi)/ÂÀ„—aeå%ùô¢ÇR;xfïÍ:ô×Nã«L`ye×ÀjYH` !„(;L@˜Ð1!’ ,‚ÃÍ•XÌre¢ÄOê"ô"¼øñ"É’|zü"Îi™¾ß–R 9›À²÷¼•M±W- ,!„e‰&Å–Å(Ùq^ŒøÿR"'ïÚvœw1ú êþܼÌê ¹vÚÖô¼T¨I`µ $°„B”-^TäÅ1ùXªÔÝVÌâ“— ½˜h)%žê;/ïœÆ\;¯DËAK!DY“ Œ‹W­ZÖ­[jjjÂÆã&¾Šõ‚ªS§N¡k×®¡sçÎYBÑ À›BA€0èÖ­[܇X¨®®.,QX¾½ÈBQžH`‰MaPQQQ°¾˜êÒ¥KX¿~}Üd½ª³Pņ¸Â’EŸÒ·ô±,XBQ~H`‰MÆDÂÀ^#°\mذ¡ ®$²ò1áäÅ*}‰¸â¯Ä•B”/Xb“1aàÿGXyqXùxñdýgBËþ—ÀBˆòDKl& |0¶\ƒÇ÷_ÚŸB!Ê ,±ÙÔ7ÛMb+Ÿbý%a%„ÍF“ XX¢É`BQælL¶MF™ÜË™‡„Bˆ¦a}¶Õ„&Y²`•7…ÆŒÍ]!„¢Ü©®Ý6[dÉwS¾ðÙ‘‰²s¶uͶm²íÿÔþåu§Ú÷Û}ÎB!D& Të²mU¶UeÛgµy½6|)¸Œ,Xå:j›`eí>n’ŽáK%„Bˆ|L`ù±tmøÒ’µIH`•/Ü—ªÛ„ÔšðÅçÚ!Èz%„BÔ‡Y±Ö×nˆ+,WŒ­Œ±Â&¸ %°ÊYëÝkn ,WL`0q%‘%„B|•î¯-S×ÕþÝ$qXåÝþÿŠPW\… %„Bä±1ùCøRhÙÿ roØ+°"y-„Bˆ†ág n›™¦Aƒpë¢]#÷ !„m™Ü/„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„BÑ–ùÿYSª5Ë#–BIEND®B`‚libfreemarker-java-2.3.19.orig/src/manual/docgen-originals/figures/tree_with_alpha.png0000644000175000017500000002410011723544471030434 0ustar ebourgebourg‰PNG  IHDRÒ¿‹ó‚Æ+tEXtCreation TimeK 31 dec. 2002 00:34:42 +0100oRÀ°tIMEÒ 9’ÿŽ¿ pHYs ð ðB¬4˜gAMA± üa'˜IDATxÚì] ”TÕ™þ«ªkí•^°i@\0*"ˆ (·D 9"Äã–“€ÛÌ™1s2É$g&:&ÌÉÍŒ&1êŒcLt" &‘Ía–Ʋ4²ô¾TwU×>÷ë÷n׭ׯª_uUu×r¿sþS]]¯ê½÷¿ÿ»ÿïýï‰$$$$$$$$$$$$$$$$$$$² ¦±¾€‡žþ#c}QÉCita^MŸH¢Hä$‘FеYx-ebQ?ó3 Bœ°F$¡r’H™÷ötŸûûŽORqBI2e)$‘2 è×¼ÐÊPÀÿü¼e+]‹ïyÔT=qZÌAápˆ·n 7òd¸¯»ã@Wë©¿bÿ™<¤JôN’LYKê?!ᜥÈzóD¿XpÛýew<úCSqyÕÐMfîtºàŠ…¦Ýxs\yU­ÍÝÙº‹†ö™ˆ$‘²’H™B:ÁUýëøÉÓg¬xb]#TÂ/”Ž«¡"«Ý²÷£·Ïø}›)é!ÅA8©$²æ±¾€<`8/àë¿~Ñ]Ù]eã }ñòî$GI¹£fâÔ¹ìm1')õ“È2H"e0x;‹íL¦]døK6g1UÕžku––_ÊÞÂ…9˜XI)«!‰” x¤šIç¹ÌKQ2_´ÚT9a õ÷õ–‘B";E‰$NèJd’zÈIÁlw{‚~_¤·«-©/†ƒÁ€··«Aðœ¤GÊbH”~ ¦ÿ|~dïép8ÜqæX£á/÷÷õ;>ÄØB yD1SüÔ"‰1„$Rz1˜Å@JX6; úv¬5ìéé4ôŸlx-ÒròH‘ÇÝ5½LŠGâ¿ ±KBe äðwz %Ð&ËdyÀïÝôyÏgŸ:ëgÍÁ¼RÜ9¶;½þOù#áȯýý}ÇØ¿na2“ bóÍÇÓžWbŒ!‰”ôô]&·3ùɳ‰|l2™ÝG÷m[Ðvú˜eÒôKMÚ¡ð`ÀOw¼O¯ýèa¯ÏÓ»«§£ùMöïϘl&å}•ÉULÚ™ ä Q,‰$¡ÆRù#ƒhÀ0ôK˜|›ÉT&o1ù)^ó? X‰£¤ì:³Ùü„³¤¢òšå_sŒ?i kn:D'í4}ºÛÏH·ÑÝÙºÂ`°Áͤ—”¹¤EL–1ibòL>aÒOú™â2c|”!‰”´BصšÉ<&o3yƒÁû2Œ¸!ž¦Ú®[ÊkêfY­áPh†ÉlþÔÛÛÓäéîØð÷Ÿ$…ȱã$òªÿCòj5“/2YN’PYI$cHD mL^!%‹·`O$S )­ð^ÿHJ(ˆ‘ÙÞ B$Ú¾Q-“›™ÜJ’PY9”ÃèRðQ4¬˜‡W/Þƒ £»FýÓ-üß#'QH¸œç4“Ÿ3ùRõw$ 5¦IF= H4^í²æñ~Ó,R ÿ›LÎB˜~Ux8‡ÿ5×¥7 .=ÔC)é$ve+ÿMN¦‹™¼Êäk¤¬=‚Ç‚Gê§ØE}aÍõ™…ß’„ÊÈÐ. q(‚ á8y´KÃÅ5Dü;\êgÜq"q(v¿Æ°z Í{J†|cI¤Ø‚IL¾ÄäR :B±žÀ(¸aН¢wâ R´F_Vž¨VCD8‡$T– ‰@0¸¿a²‡¢!T*ÒB 9Â:¢gÔâo‹a¥$Ô£‰”ˆ@Ïd7)ž!ÝâŸi4B#3`~¬$T ˆd”@ÜøDÏ‘*2 I¨,@!)_ ¤…$Ô"Ÿ‰” 8yr@ZHBò‘H"*™ÜËäNJŽ@âßâ(Qî$Ô("Ÿˆ$¨œÉMLV1é¢ä ”O# 5 È"Å#ðK&ï‘2ÁYhÒB*ƒÈe" G ?’øYèÒB*ÈE"%C ~ZÂèåÚHB¥¹D$I Ì@* È"I$¡R@6I$ª.dò-õ3I ÌAjÈF"i „¥ Éd")í}’ HB%l"R<KJežg(ZXDhô eÙ@¤dÄ3²%F’P "%Z®æ{ÉHo)ƒ6.›ˆ^•!SÉVd ¡FjwA*,ÑÃO´Æ†eƒ@W3Áž©œ@(®È Ä×HFv6H¼w^·a6TT]ÁäE—˜swêËfˆÏ_¬Iž‰š&sµ»Œb$%‹¹Âð]ÅÞ§©ÿsÙD"h•o×R´¼ï™üˆÉG¤TÐáŠ'Š’&¨y«ôd;´zC¡™ê½#…‰WØd³ý~DˆñâßÚ•¾¨×‡•ÇxÞ¥L¾NJ™ç&­êñz¥˜µD5jw£†dOÆo¦nü¹Óo ü_õ÷{&[Šl®H$ì¶Ú¡€ïåΖS(ÒMÑz¼¥Á÷ya‘+˜ü–’ó@ŠÍÈÎÅêmòôÛ˜ŽVø}ÞifKQ5»üf«Í¹½­§ýìvRŒŠAáF.+ÝJ %kôô¯0`wâNð×_2D¸yGqYƒÍáz¶¢¦nâ̹Kœ—/¾Ã\Zyµ4¢ë_ Ý·µ¯·»ý€§§sM8^>oÙ}Ì.JcŠD"ÔÛÙJo­{ÚÓ¸ý½ãg›R¿‹uØM-.jÃÖ(: 4R½`zCÑHI[m5×ÈÄu0RB½Äd'Ó×|WYÅ +×2ý­2bw\b¡ÍŒêÏHi0,q–”½Înfü¢»¶a¯Ó!šLdwÓ…sYO~ºÛÕÝvæÆ€Ï‹£7ÿBJ(×)(“H¿¤%U®häzû󇻽y ]>¢øð\ÃHúPØC÷&7°†è¦¿ÊEw=bTõL›hb£;ö™Ð'*¯®›0Ÿµfsbþ¡ÅXzßãÅV‡«ÎfwýŠWÝLJ'#VâP¶XÓM; 0*ñm‘¼ÞV®--²;®¶»JfRp…÷Q™5×÷ÕFⳂ÷|Øü,| 3ýÕÎ_¶:YýÍMý!NlÃÀ¬«—8´›dÅCmý ª®«7—UŸƒÒ¼Åê ñmÃ)–H¹N ”ôV5aŠ«t\ÍŠß9Û瘌À¡øÿÚ­6{ÝEó(Ûõ7‘xxRãóöM¹dÁ͆÷œe,;nyQ8žCÊ6&œD¢'É“Ëa\&ô†>%o€òÁ#i‘ˆP\ÊYˆvn.èÏèVY펪º©IýxíÔ™,|5'eÞ„ûe­â´EFrD"RÕZT¡|ÝÕ\K(Ñ6ÊrEFC»–P(Ð×ô鮤~üð®?…M&ó UYü\Ú%ßùâ…´HMofóqõ-B’|óFz'£9©šsEFB; Ëî,Ù¿wÓÛA 5§§“·m †‚þK–\Jé)R×[`@o@>z¡xÐÚG‡ÝYœúŽHƒC•A¿ï‡woòvµ|nè‡OÜqw¶vwµœÞG±îZoØ3ß½í§¡^»PÀm„µÃþœÐßpóHƒiýw§ÙRtmwËéª ¯Zle±kÜ/µ:J¿þÁƒ==mg~ð÷ƒH˜Xäû¢b’ŒOå«q¤CoûU}q½‰‹ùª7\])ØÝ¨éÏ0‘pÁ€WoWÛu˜ôª™8E-åd)² ·zdÏÇ‘›éhÙæîlÁ,߯ Ï!ã-E>B_ow–×L:Ï¢«·Ý›é•<Èh׺…éíUg\ Eo‰õgÜî~GQ¹Õ׌êÏHÜÈW¤¢)À0öŒÒŠš§0é…ñz 5b”„¹_jܺÁ·ê÷ömðöõ «¹G½T;íTßÃ#ñeùl¢Þ0zt‹«tÜsvWq¤jB½UGoÁþ>·Ççí}†”$^·ª3$±"““)ßõ¦§¿¨ÝÙì×1»³Ï¾þVÓ þ¶¬÷vµº}^Ï;Ìî>Põ[ëRõ—q»3B$q Æä16_™ãòêºë,Ël‹Õf‰„C~Ÿ·owûé‘H˜_¸G½ .Ú–!ŸCž?†áW ž€û·9Š[QSw¥Ùbžk2™/f²××ß·¥ãLSÓÛ*RòѢºT© 1´ƒÝÁõ`úQM‘Õöcfw>›Ãé°»PÈïéíò±>‘‰éïeRì«WÕÚeÌìøQ´ô¯Ùçé=ÐÒtè8)­…b³ø¾¨ w­ZCÈwcà÷},#%ûýa_{ËÉÃHÈÄrï“’ Ó¥ê›3#Ñd:K¹Ÿ°šªþÄ 袜…y%ígŽ#o 5ÏX@™¶ÇH±MÞ•ˆ×7ʈ.5ç7Þsbá†l›C‡ãøÝ<7£-B£žÉƒ¤d2"¥áúÔÏÑØ Õ„>1d‹uZ÷0Ag¹<¸áÃn`O×09ÀËsÁæ@èK'¦“²²:ÕÆÛhfƒè•xëЧÞbÐv&m¤¬rlUßó>‘èV żÅwT=ü·ª;4,½ê+Q4 áñ<|§0Y¢ê Ю6.ˆv‡ÆúzRʱÁ¦ SÞ‡„ͽ«~ŽcyRëÍ3fwÉ?á7%þ h« îú­Mʧ<:#à¿ÉR&’Ò¸ á‹Í|ª.ðÚGÑd̓¤x¯UL>fÒHÑu;\‡\Ï…Üë%¤ôÏwR´Ÿ-Nêc±èjRj4Ó(¯.6œ (Üè™`<|ãîÔCÑpޝŽ-4O©b²–ÉRúCDÑp˜¯~%Òß %|ùE.ó5×Î(°ào+)Þ‡GEÜî Íêç7ÒŒl&K$@›ˆ#Ú¡HðÑ&Ô¥¨#eI}PýŒ{q> K«C¾<Þëy&óI1 î‘ %ß#v^œKJ¡€Bˆ^Q…êJ&5¤¿*wÌríA/kW”B#ÀÖ¥¤¬îÐ æz—ðSOø#wÿEÊh*æpñ…D¦ËÕ׃‚ÎD]ò†a0^£7*$â'Jò9 Õ(ð°Ç?AÊè2xöˆ^CÃ!&ôòÏÑÚ¾¨~¾Š¢#£"™òH¼Áø2“õ¤ ms}é5@^õ¸U_Úš¬ôH±à…;† NŸ—†.fÔv€µõ ÄcQeéYRvdG«¬Þå+™ø½Ác•õ‡[ëP»‡ÿz©§SÔ#eÜ3I"¥œDØ1ãÛL^'eˆë7^Ø«mk‹£w0© ¨G*2a¥+†º?îSK$ñi☻™bûH’H9<xЇÕ÷/QüJ±Ã‘H|#RèkÕ“RÖŒ{¥|xà:Å=cŽˆr&*mÌuý6)µäËIŸDc²BV"1øBÙ1d$ü˜”Éi½Îȼ†ÞJQÌæ#•è~&R¬GÊG¯Äï§žÉL> Ø†Ioa¨øú¤ô1ç~x—vH"¥þÀr=Îd3 }èbH—Ì@Œ6ÄC¸ˆ¹%?DÆ÷LùH$¢hㄼÄÓÂý%ªUÇ?C(ˆ0–ÓЄ1«Ù ‘|T ÛŸ’bôñŒN è < æ9R†v‘>ĽR>†x|ôóNRŠŠŠS‰H$zó¤x³:…AI¤‘ƒwdg‘2À€Ðë0Å0ˆ!ÝH¦DÃ(”¹%näa1»•â2hõ)ê ž I‹(vÐAz¤,OJÅB,HD"1OÑ´-,qÿ êç«(?ç–ø=€èŠýÍἺ¨3èê7L¾HÊZ&鑲âþ‰”«—â'í¦’÷¥ý½|ž[â×Ñ6$û®'}od„L8Óhl."}¯”6=I"%þ{ÿ5E“RÅ 1 (•ÒczC»ù>·„뾌l§Øzˆz£t‰ô†e[˜üe¸Ÿ$‰”µá0Y1 ^KúDJ‹ž$‘’W<6Kö?£èfi@2“¯ÉBÅËǹ%m¦÷FJ>¬Óê ‚DWôa~¦CZ ‰dÜ0Ñqý) ÌÐÚÅ éÒý.¦ÂäëÜ®ln¾ ‘hd{q}ayE¼DÖ´y%I¤ä}a’k^ÒáÇË`ÈD&¼và!æ–D/kFŽÖyhèhQ¯[YµýÉ´ô›$‘ô¡Ý®‘+»h£ÃRâ¤Ôx$Òk“m!Ì-‰DÒ„Èriu‹kÆ2q,)ßLÑáüDé@‰ ê á7Y—Q4‡b¥h%"½ÐØ0$‘b¡m‹Aè„RYXñsŠ*[Û/C°áΡ}/>ÄxÓèÜ’h$¢ŒØXÒ¬c^³«Y±$Bø…þÌqõ>ôìs$óp<‘}[Œr¢2õAZ B nž¢[À$íÑ“)~’Ͻ”‰‡[MJÅÓnõ,ûÆÙSêÿx1½4 xçàlWÏýãÁž¡¡#sÚu6"Äãð»0>Ì-}”0Ãñ0ˆ2õ÷Q#¯“†vÚG{[Ø]%•3®\|GÇÙ¦ì}]OGKu(èï·:\Eá`àÍî¶3NŠ.ÁRj„ç÷†‚Ê«'zŽÉÓo |+ü>ï4³¥ˆ‘5Òlµ9÷±÷¯±s LëP“WÊî7¹÷Á úK*k§¼Ï¿9ÖXœØ#cIÈÞ>¿¹éÐϙλ²ánÛ7|‰B¡ µž?´'d¶˜ÏR4!™Éd|Þ úš>Ý•ÔyïúSØd6Wßšœ-T"¥CÉètÆS²)Mç 1>GºÐds8O~²áµÑC#èïë!vO!³¹h§ªëd²1ø1]vgÉþ½›Þ=/ö£mܶ1ÈBòê¿ 5,…H¤t*9^î¥ñæ1:G:á5™‹^ùdã«S‡÷úÂþߥ®ÖÓîÞ®6N¤%­búðîMÞ®–ÿoïêb㨮ðñ®³v6bRhQ¢´€„Z(‰”´$P µ*j«*¥om%¤>ÀHí ­TúVÚ>T¥-‚¶jCQB â'! jŠƒIJ“ˆ8d“Øëuvíýï|ž9ÞëñŽwÖÞ½3³s>éʬ½ËÙܹߜ3÷œ{¾O\Ù=wòX:ÈÉÄÈ ª£X6ŒDjö$ÏúïÛhÔ\O“ÀëvÞåÔ®_?^‘çÃ…3C´÷Ù§& ùìNc` šÓ n{²í*9&Ó©{~÷dy¢ù€Ðó¥gžHALÜÒAιµÆ<ÒL]1±c‘hû¦ñÄÈÊuwmí@Á ˜äiùù+÷æsS¨ÛB2ÖI§”ZÈFCæÚÙX|Å`v2½åÌñ·—Äû¢ñU‰V– ¹Á×wÒóOý ›ÏNL&.ìµ¾Û„5X‰O=óUËn±Ï žm3ògÈõôÆ)ÚÞ1ófûÌ{‡ÊÓó2š821–ØM-ZWvCM$ªLò–ó'-ï_óÙˆ‹I†â8/<š®¦ÔÞÌ ©ÃF£„ºfæ{r"™ÊMe–JÅë_ûÇ§Ž½1ÈÉOehèà?á ‡^þCÖø·ì¿rbk\YÀß³ž2¡»†w¹6ymü(’ÐH¶¾ÿöžh:y5’NµÜý{zù·?ÉÝ÷ün.Ö¼°d«k»a-âbOܺ±ûöÍØÒå?íìém_¹ú¦l cWË—èƒw^)§“—“ÙÉÌ^#D@U„¬_Ê:¹(]añ°RØ*_ß·¬ÿq$B‘ÃQm ÞÚ²q„†Öÿ1é‹ÅLá(™¹7ÔÅ—_¿æ¶®%}Û3©Ñ{ñψD"¹h´}(5véáP_Ç )eÎnZóÙÅüôX×y’І'ÜFïˆvtFË¥bÎð’Ç¯Žœ¶Â9VL)£¦Ý°‰'Û¾X€¿2ÆHWOlȘä{¢íí·OOr±˜3¢¦öä募“ü"Uô^Ç•¡ŠMÛ½E³/¤ÖŲˆ¹VÏñ÷ÄÀÖ{Üú]„*žPüV½B½àl×¹[±£ÙyÀ6›Ý U¢ WvÃL$L2& ˜?ãgdž?â æ%r-Ðrý%™’”|—T qwªünö…Ô¶X0ßü=ñz¬Á"T!“ªËC­„w[h'±Ý.çù$.‹±kúÖÔAûÁ>\´MdŒû̉Ƥ©§IA¼[Kf£9xá©êÚv¨êïüšÕøp¡ê¹%m,j§Ù\•ïÈÉ`þŽ|V*§ {ŸÀzíª¯sÖud»ê¼©z¾ªò¼vÃN$,2ôPC“G,&nu«nH`@ŸMOÐF½{׺¸:.¤¶Å²HØÛ6óÉbš«Cª–.ÿ\èI^»]¾éØ+RªuÈu­…v"¡•-Îî¿I•;¤}ab¢ÑÕô»dö8NÕÏ9AÇ…Ô²Xõè<“ÉÞÁÇÞ“¢Ç;T»ê¿ßž„¶'~]÷k+‘x¿b $%/YsaO¾ñ{~€LèóýoZø]±iR“F@%?·µÕx_#¾›j“I\mnêíV40Ií艰îÖkõNÎwk~?B#4ƒ„š–\ Ù~Ô»©šz!5ÚhÔïàD¤fÛµÛ^°Í0–˜¼;­Ÿ'¬yP;˜ª1:tþĦėiq­oUP¬2fé°ÑH”©ñh!¶Œ0‰I•=lTkÔnX|ï ·ó52·NÕöVÇâñb† a#/x4 ø‚1ÞPæÀ©×›:ÐG ÄÏS%?á·¦6"¼É€0í4ÍU<(; ü ‡ÌÐN^‰ Ô šD‚E"lDšîq@f£v„uœÄ¬æöíX»ÞNÕ ÁC˜ˆÄ‹!” Þ¢¹aÓn–ú;Uo§Z“zAF"}•L‘®Kä,Rí¡œÿŽª†fl:Œ°Éž;ÚIsŸjÉÎɦƒÀa!P-w¸MPʦƒÀa!’ÛÜ‘›ÊÙtÌAˆä6wä&i)›‚ª‘€zrGµ ›‚9‘’;r‚l:ª¢Õ‰´˜Ü‘æÛt2…­J${u6T;JÐìݺ…h¨ÖÚtð³’¸ Ih5"©Í.¸»ô‘;ÚE³ûT««s Õƒ¡×ž½6Ñl%tUQÜk%qA“Ñ*ûœTɯãë=‘¹¸ùÜQ#Ž/c ç¼Ò·Œ~qÜ» •è:dW<×­$.ЀV Ò¼ªä‘H´m*3ùDÌIr~! ZýÌG±øÊ[;»z^,ä³Ël²óÏYJâIÒ¯$.Є ‡5Ãî{¡ü¿G æ=”I>Y*Ï’Ù]‡[ôº÷µÏÛt—ÓîXŸa;öt|Õê›-%ñ6Ÿ(‰ 4"ÈDªS•ü‰ÌIS1üÇdªy£¹£ªH^Ï‚ž. ²l?»mÇc†í‡k©•ëThFP›è/F1|¢îJ±zÛVè·¶u)‰ 4#È»v W ïé]Gf;_»2¹[ %ñ}¬$.ÐŒ iqŠá+úQ.¤.æzÔ¼ý®$.ðA$R#TÉYÍ»^ÔHÛâ‘ZA$£Qªä QóÖ&;/‚J$/Õ¼ƒ¢$.Ј I»ô»Ol |Œ I»ô»Ol |Œ æ‘t©’ûͶÀÇ4‘H¿š÷bm×RDo´ä¤@‚Ÿ{©æ]í‚Ažbn2³Ó°ý/ª(tÃö(UˆÜh%qf•H^ªy»¶=•ž83úéùårù7d*dEô$UѹpVž—Œ  ðRÍ»–m5Ñûm2…ÉöÓ\EôIZXõ¹Àgâ3’êÑoS•»ùÈ?ñ3 W`/FÍÛÉvN±›rFX™¤êG8ÄA>Øç¥š÷|¶Yǭߣ {åF6â”®À'hÄP=+”óÈÚ“¨QG¾¼“áz:  ‘êQFøAöH /Õ¼l«Œ0ÇØ±{ˆÌ>g­Ïºq­æ‘ø§“l³ØmÛ¿ž“6’¹ò’&(-‡V"c>éÊf/X'un¶¼}d†|^*y Œ ÖÚÕ¯©Ý#Á"s»üvšÝÀRH¶ZÑ#ù *Ià…Ðoïc¼FΞK@´ºGòööƯ“Ùp_mo,^© I8”CYúE`{|˜ä9©e Dj>Ú”ŸðJ˜óo¹é –& ™ íšÑT Ä#é“•·©Ù„f‘jbX6 ñHzऩ„Jrn‘ôAõ6б…ä ªÔðN: Ú郺é€z<œY‚®í~ëµê±ˆ$¼ Ä#éƒ}Óá 2umo¥Ù9%iÓ@ˆGÒ& n óœÒ;$•†x$½P‰‚ú»=Ƹ›ÌíðjÞH¼R@ DÒ•L8R<ìàU ï„vú¡zT6,3Æ2OÏ6òС@#Ä#é‡ýYèUc|Îkɼ±ñ͇A<’wàBV´æú¢1Vcæ&e%Q‘¼J Q¾Gæ1 l<¬±þ–'ñL@+4? "Ò©„‰ÅWÞÐÕÕó÷|>»4ÚÞ¹¤\.Mttur¹ç’—/&³'w(²÷Ÿx ¹»yöDÑîXßöÎîØÓñU«×nظ­ãέ_oë[q=%Ο¢w_ùKáã¡ÃékãW?ȤÆ- S¥Í—J(!“Ç"yƒéþáݱ¥Û–ôÅÿ¸mÇcñ»x¸êç* bvmì2½ôÌ™á£ÎŽ~zþGƯÿK•.±B&Ÿ@ž‘ôƒ½Ñ@OïÒ¿mÛñèu[z¤³£³{îÛÚ¨«'Fë¾´¥Ò1W/­ÍMepôÂÞ£Oz Ùþöm×}æÖã«VßóÀ÷;#‘ùïgðTÛw<Öé¨^Ù°_TÑ}!’~`Áw ¹ïlØx_÷’¥Ë]}膵ë úK}Ëûï£ ‘¸Ç¸ìæy !’^pXןLßtÛ½÷»žãŠ bV*•î"S>F<’ Dò«Ú;ººWÜ\ׇ hà:2=HÄŠ’còB$ýÀbO‹ùôùëúàéÁ7Km‘ÈYë%ËÆˆ7ò„HzÁ >ÙÕÓ{âý·ö°Åív>òj¡˜Ï½kýJ¼ DÒ‹™{…\öϧ¿5™L|âêƒçN+CT:™9AsÕ,CòHzÁ$2•™‹DÛ7'FV®»kk‡ñÌäø¡+>¦~þÃTêÊŽùÜÔ™Ò,á©&f…TAˆ¤3D2F±Ï ^K^ÙŒdkÿ·Ñ^œ¢í3oF8wæ½Cåi&ŽLŒ%vSE?Y‹–ÕEÐÙ#H|­¬âIÌõ}ËúG²y"lqcwÎûhøðþ¹Üdzÿd:…ƒ8r¡€uÌzr!ÔÞ‰2º‡"éÇt™dB.9¡e¨Xˆ¯ØFïˆvtFË¥b.;™>~uäÜp¹\bÂÀ¥”ÐNõHÚy!’7à¦È¡Èdêµ~ÂKÁ[!ÆãÆûx³ˆ”¶þ›Ÿ$¬órÉpÑi^yÍJìð< —þ”­÷ÁóLQ¥òC<‘O Dòjƒõ5ˆOà ü7,o >‹T ÊNÉcHhç-T-YnzÒN³–3É@&zIH䑼‡ÚØÄ©7ƒýü‘´ëò„HþAµÎA ieìs‘ü ;‘@ jàÿ½þ]–Ë?IEND®B`‚libfreemarker-java-2.3.19.orig/src/manual/docgen-help/0000755000175000017500000000000012164627123022063 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/src/manual/docgen-help/editors-readme.txt0000644000175000017500000001012511723544471025533 0ustar ebourgebourgGuide to FreeMarker Manual for Editors ====================================== Non-technical ------------- - The Template Authror's Guide is for Web designers. Assume that a designer is not a programmer, (s)he doesn't even know what is Java. Forget that FM is implemented in Java when you edit the Template Authror's Guide. Try to avoid technical writing. - In the Guide chapters, be careful not to mention things that were not explained earlier. The Guide chapters should be understandable if you read them continuously. - If you add a new topic or term, don't forget to add it to the Index. Also, consider adding entries for it to the Glossary. - Don't use too sophisticated English. Use basic words and grammar. Technical --------- - For the editing use XXE (XMLmind XML Editor), with its default XML *source* formatting settings (identation, max line length and like). You should install the "DocBook 5 for Freemarker" addon, which you can find insode the "docgen" top-level SVN module. - The HTML is generated with Docgen (docgen.jar), which will check some of the rules described here. To invoke it, issue "ant manual" from the root of the "freemarker" module. (Note: you may need to check out and build "docgen" first.) - Understand all document conventions in the Preface chapter. Note that all "programlisting"-s should have a "role" attribute with a value that is either: "template", "dataModel", "output", "metaTemplate" or "unspecified". (If you miss this, the XXE addon will show the "programlisting" in red.) - Verbatim content in flow text: * In flow text, all data object names, class names, FTL fragments, HTML fragments, and all other verbatim content is inside "literal" element. * Use replaceable element inside literal element for replaceable parts and meta-variables like: condition> templateDir/copyright.ftl - Hierarchy: * The hierarchy should look like: book -> part -> chapter -> section -> section -> section -> section where the "part" and the "section"-s are optional. Instead of chapter you may have "preface" or "appendix". * Don't use "sect1", "sect2", etc. Instead nest "section"-s into each other, but not deeper than 3 levels. * Use "simplesect" if you want to divide up something visually, but you don't want those sections to appear in the ToC, or go into theor own HTML page. "simplesect"-s can appear under all "section" nesting levels, and they always look the same regardless of the "section" nesting levels. - Lists: * When you have list where the list items are short (a few words), you should give spacing="compact" to the "itemizedlist" or "orderedlist" element. * Don't putting listings inside "para"-s. Put them between "para"-s instead. - Xrefs, id-s, links: * id-s of parts, chapters, sections and similar elements must contain US-ASCII lower case letters, US-ASCII nubers, and underscore only. id-s of parts and chapters are used as the filenames of HTML-s generated for that block. When you find out the id, deduce it from the positin in the ToC hirearchy. The underscore is used as the separator between the path steps. * All other id-s must use prefix: - example: E.g.: id="example.foreach" - ref: Reference information... * directive: about a directive. E.g.: "ref.directive.foreach" * builtin - gloss: Term in the Glossary - topic: The recommended point of document in a certain topic * designer: for designers. E.g.: id="topic.designer.methodDataObject" * programmer: for programmers * or omit the secondary cathegoty if it is for everybody - misc: Anything doesn't fit in the above cathegories * When you refer to a part, chapter or section, often you should use xref, not link. The xreflabel attribute of the link-end should not be set; then it's deduced from the titles. - The "book" element must have this attribute: conformance="docgen" libfreemarker-java-2.3.19.orig/README.txt0000644000175000017500000000301711723544472017336 0ustar ebourgebourgThis is the README.txt file comes with the FreeMarker 2.3.19 distribution. For the latest version of FreeMarker visit the FreeMarker homepage: http://freemarker.org/ (mirror: http://freemarker.sourceforge.net/) What is FreeMarker? ------------------- FreeMarker is a Java tool to generate text output based on templates. It is designed to be practical as a template engine to generate web pages and particularly for servlet-based page production that follows the MVC (Model View Controller) pattern. That is, you can separate the work of Java programmers and website designers - Java programmers needn't know how to design nice websites, and website designers needn't know Java programming. Licensing --------- FreeMarker is licensed under a liberal BSD-style open source license. This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. See LICENSE.txt for more details. Documentation ------------- Documentation is available in the docs directory of this distribution; open docs/index.html. Installing ---------- No real installation needed. Simply copy lib/freemarker.jar to a location where your Java application's ClassLoader will find it. For example, if you use FreeMarker in a web application, you probably want to put freemarker.jar into the WEB-INF/lib directory of your web application. History ------- See: docs/docs/app_versions.html Or online: http://freemarker.org/docs/app_versions.html Mirror: http://freemarker.sourceforge.net/docs/app_versions.htmllibfreemarker-java-2.3.19.orig/examples/0000755000175000017500000000000012164627123017450 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jython-webapp/0000755000175000017500000000000012164627123022237 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jython-webapp/displayTwitInfo.html0000644000175000017500000000056211723544471026265 0ustar ebourgebourg<#assign twit=RequestParameters.twit> <#assign title="Upper Class Twit of the Year contestant info - " + twit> ${title}

${title}

<#assign info=Application.twits[twit]>

Biographical information: ${info[0]}

Ended the contest by: ${info[1]}

Placement: ${info[2]}

libfreemarker-java-2.3.19.orig/examples/jython-webapp/WEB-INF/0000755000175000017500000000000012164627123023266 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jython-webapp/WEB-INF/web.xml0000644000175000017500000000217511723544471024576 0ustar ebourgebourg FreeMarker Jython Example twitOfTheYear UpperClassTwitOfTheYearServlet TemplatePath / TemplateDelay 0 NoCache true ObjectWrapper jython twitOfTheYear *.html index.html libfreemarker-java-2.3.19.orig/examples/jython-webapp/WEB-INF/UpperClassTwitOfTheYearServlet.py0000644000175000017500000000174211723544471031715 0ustar ebourgebourgfrom freemarker.ext import servlet class UpperClassTwitOfTheYearServlet(servlet.FreemarkerServlet): def initializeServletContext(self, request, response): twits = {'Vivian Smith-Smythe-Smith of Kensington' : ('O-level in chemo-hygiene', 'shooting himself', 'runner up'), \ 'Simon Zinc-Trumpet-Harris': ('married to a very attractive table lamp', 'being shot by Nigel', 'not known'), \ 'Nigel Incubator-Jones of Henley': ('his best friend is a tree and in his spare time he \'s a stockbroker', 'shooting himself', 'third place'), \ 'Gervaise Brook-Hampster of Kensington and Weybridge': ('is in the Guards and his father uses him as a wastebasket', 'shooting himself', 'winner'), \ 'Oliver St John Mollusc': ('Harrow and the Guards, thought by many to be this year\'s outstanding twit', 'running himself over with a car', 'not known') \ } self.servletContext.setAttribute('twits', twits) libfreemarker-java-2.3.19.orig/examples/jython-webapp/index.html0000644000175000017500000000056411723544472024246 0ustar ebourgebourg <#assign title="Upper Class Twit of the Year contestant info"> ${title}

${title}

Select a twit:

libfreemarker-java-2.3.19.orig/examples/webapp1/0000755000175000017500000000000012164627123021007 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/0000755000175000017500000000000012164627123022036 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/web.xml0000644000175000017500000000112311723544471023336 0ustar ebourgebourg FreeMarker Example Web Application 1 hello example.HelloServlet hello /hello help.html libfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/templates/0000755000175000017500000000000012164627123024034 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/templates/test.ftl0000644000175000017500000000015711723544470025530 0ustar ebourgebourg FreeMarker Example Web Application 1 ${message} libfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/classes/0000755000175000017500000000000011723544471023477 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/classes/example/0000755000175000017500000000000012164627123025126 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp1/WEB-INF/classes/example/HelloServlet.java0000644000175000017500000000360211723544471030406 0ustar ebourgebourgpackage example; import java.util.*; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import freemarker.template.*; /** * This Servlet does not do anything useful, just prints "Hello World!". The * intent is to help you to get started if you want to build your own Controller * servlet that uses FreeMarker for the View. For more advanced example, see the * 2nd Web application example. */ public class HelloServlet extends HttpServlet { private Configuration cfg; public void init() { // Initialize the FreeMarker configuration; // - Create a configuration instance cfg = new Configuration(); // - Templates are stoted in the WEB-INF/templates directory of the Web app. cfg.setServletContextForTemplateLoading( getServletContext(), "WEB-INF/templates"); // In a real-world application various other settings should be explicitly // set here, but for the sake of brevity we leave it out now. See the // "webapp2" example for them. } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Build the data-model Map root = new HashMap(); root.put("message", "Hello World!"); // Get the templat object Template t = cfg.getTemplate("test.ftl"); // Prepare the HTTP response: // - Use the charset of template for the output // - Use text/html MIME-type resp.setContentType("text/html; charset=" + t.getEncoding()); Writer out = resp.getWriter(); // Merge the data-model and the template try { t.process(root, out); } catch (TemplateException e) { throw new ServletException( "Error while processing FreeMarker template", e); } } }libfreemarker-java-2.3.19.orig/examples/webapp1/help.html0000644000175000017500000000121511723544471022630 0ustar ebourgebourg FreeMarker Example Web Application 1 - Help

FreeMarker Example Web Application 1

To try this example you should visit http://yourServer/thisWebApp/hello

What's this example about?

This Servlet does not do anything useful, just prints "Hello World!". The intent is to help you to get started if you want to build your own Controller servlet that uses FreeMarker for the View. For more advanced example, see the 2nd Web application example. libfreemarker-java-2.3.19.orig/examples/jsp-webapp/0000755000175000017500000000000012164627123021520 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/0000755000175000017500000000000012164627123022547 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/web.xml0000644000175000017500000000043611723544470024054 0ustar ebourgebourg FreeMarker Example: Embedding FTL into JSP libfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/fmtag.tld0000644000175000017500000000117611723544467024370 0ustar ebourgebourg 2.0 1.1 FreeMarker JSP Support template freemarker.ext.jsp.FreemarkerTag tagdependent Allows evaluation of FreeMarker templates inside JSP caching false libfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/classes/0000755000175000017500000000000011723544471024210 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/classes/freemarker/0000755000175000017500000000000011723544471026333 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/classes/freemarker/examples/0000755000175000017500000000000011723544471030151 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/classes/freemarker/examples/jsp/0000755000175000017500000000000012164627123030741 5ustar ebourgebourg././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootlibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/classes/freemarker/examples/jsp/SimpleBean.javalibfreemarker-java-2.3.19.orig/examples/jsp-webapp/WEB-INF/classes/freemarker/examples/jsp/SimpleBea0000644000175000017500000000564711723544471032545 0ustar ebourgebourg/* * Copyright (c) 2003 The Visigoth Software Society. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Visigoth Software Society (http://www.visigoths.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the * project contributors may be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact visigoths@visigoths.org. * * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" * nor may "FreeMarker" or "Visigoth" appear in their names * without prior written permission of the Visigoth Software Society. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Visigoth Software Society. For more * information on the Visigoth Software Society, please see * http://www.visigoths.org/ */ package freemarker.examples.jsp; public class SimpleBean { private static String[] arr = { "a","b","c","d"}; private String theString = "Hello from " + toString(); public void setString( String foo ) { theString = foo; } public String getString() { return theString; } public String[] getArray() { return arr; } } libfreemarker-java-2.3.19.orig/examples/jsp-webapp/index.jsp0000644000175000017500000000210411723544471023346 0ustar ebourgebourg<%@ taglib uri="/WEB-INF/fmtag.tld" prefix="fm" %> FreeMarker JSP Example

FreeMarker JSP example


This page is a JSP page, yet most of its contents is generated using a FreeMarker template. The below lines are the output of calling properties on a JSP-declared bean from the FreeMarker template:

<#assign mybean = page.mybean> <#assign mybeanreq = request.mybeanreq>

page: ${mybean.string} <#list mybean.array as item>
${item}
request : ${mybeanreq.string}

Note: Starting from FreeMarker 2.2 you can use custom JSP tags in FreeMarker templates. If you want to migrate from JSP to FTL (i.e. FreeMarker templates), then that's probably a better option than embedding FTL into JSP pages. libfreemarker-java-2.3.19.orig/examples/webapp2/0000755000175000017500000000000012164627123021010 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp2/poweredby_ffffff.png0000644000175000017500000000532711723544470025033 0ustar ebourgebourg‰PNG  IHDRXTúÒ,tEXtCreation TimeSzo 5 okt. 2002 00:01:59 +0100†*'tIMEÒ -5™ ì pHYs ð ðB¬4˜gAMA± üaPLTEÿÿÿùùùéééÞÞÞæææ÷÷÷ÓÓÓººº²²²¯¯¯¹¹¹ÑÑÑõõõïïïÈÈÈ———€€€}}}ŠŠŠ¨¨¨ÁÁÁýýýÊÊʈˆˆ™™™ÆÆÆ®®®ŽŽŽuuuvvv­­­ÎÎ΂‚‚äääÿÿÿþþþüüüÛÛÛqqqŒŒŒÉÉÉÌÌÌûûûúúúöööøøøôôô¶¶¶rrržžž“““±±±òòòðððñññîîîçççìììíííëëëãããáááóóóåååêêê‹‹‹ƒƒƒ„„„âââßßßÍÍÍÒÒÒÜÜÜÙÙÙÚÚÚàààÖÖÖÔÔÔèèèØØØÕÕÕ´´´«««ÝÝÝËË˽½½¼¼¼ÂÂÂÄÄÄÃÃÃÐÐÐÇÇÇÅÅÅ×××oooªªªeeeJJJ¸¸¸ÀÀÀÏÏÏkkk;;;RRR···UUU¿¿¿»»»¤¤¤DDDaaaPPPMMM¾¾¾ppp”””yyybbb¡¡¡§§§hhhµµµ‘‘‘’’’³³³¦¦¦777OOO¢¢¢œœœ```ŸŸŸTTT~~~SSS{{{555YYYiii   ¥¥¥GGG………‰‰‰xxx[[[nnnfff–––jjj@@@:::===©©©LLLZZZsssFFF£££ddd333<<<°°°VVVKKK¬¬¬QQQBBBEEE444888NNN111>>>›››\\\000666ccc|||---___,,,www]]]mmmlllzzz ???$$$///)))&&&•••"""(((ššš%%%999!!!XXX‡‡‡IIIWWW^^^†††gggÐ2vñtRNS@æØfIDATxÚ­–ý_S×Çóœ\’€J Š1 ¹!”ä’‡{IÔ<Ý<^’›1Hjxt©HI (P“8WµB±"ê6§m]Y[Y]WÛîyvvÝ¿³so€í‡ý²×xÿpÎù~Ïçûy}s’ss †¶§éÔ?oî¯k2Ê8šÎŸßlšMÕþÿÜ9÷ý‘¹ñÄ´/gâô÷¥x²aWÀÝùÆËç›D”ñ¥Ïg3¨ýçFÐdQ ÿüöŠÆ©4Q§±¹ëʈ(vf‘è¿Ä;"Q£±ÃØIífGÄôj[nk¯;(Ô2GÂr/M÷«WçÜd(÷Ý«`þGòÀª¤ð'õßµõðüGžˆí@òüêf¥&B^/þÍ•«'5=þë’Ü P‡¼Iɱ©0Î`¼¯‡Ë´mŒ~YLK43µóßö/NÝeâ/^¾|.æ§îòÓ±ÄV°üíä`õª>NÂ09þæäß«»2¿˜Œåã&çS+£. á].6-–  üû•”ÿÃZãâ݇ÅXïÃá?í¯ŽÝ®Íù}[ÁŸS‡÷,UóI¨»È¯[ GÿòY±8RÙà ¸ï ¦ £®/¡7¿øÝÆR*“]øråÑ|*º:%š½t( ?zñÕà…éèL¢PÌl'¾úbc²6Á¥ø‹¯Ï|st5Ÿù:µz('ÁáTc˜±ÙëÄ(œÏ5…êR»œ úÖGK‚¾¬,.Uz‰@"<»TìÍöF3®$±Ä×K«i—”:“}ë¥é¢|þ·¹° î`>çÃç”ñ‰Ú(ÐSd*JÜO6Z,t qB“‰Ê ÇМP–Å‘­@‘/æä¦uÅH1—pÏõ†{"À …>§³Aú÷ÄxòI`›§Èú1¥Ãã'ü‡‰Ã(²IÌáó8mÁí€Ò„T%Ëæº²! ‘ò6$‚ÚxÁmé °IÜDZ›í&Ôš¬‹=~÷0›l6e±X-vŽRi1UȲ¡6–……B‹N®SÆŸFÒa7±,o?{öìʱ‹Ð;FãèÇA»¹có7v»¥Ãh4"TîVÕÜ”÷(ç˜Ì”"ÎÑ‚·–ïLg'bè\®hð’N;²•,Ó:øi”m#?ýÌé nï´žF•fÿ5 ‘Nz¯•Ow¼×Ãm¡Ÿ ö_‘²„Üå ""î€||fC“üõí‹[,âꨜa-OàdG£{*0Z¹ÀL7B_Ž4kµZñüƒ ™ÝJþÒŸÈÈ2¯=aõ?¾ª1X÷Pc+ÿ~ÕÍ\j¬z@|òÁ‡báã¦'¼z S6Z1O<ø5p™ÍÌü)ÚØ'•újn_ˆØœ´¶¶v·¾VrÖ ùWç|û†Ø«s«ÿŠ{‡îÏCîÿY¢â½ ðA?_ÿE)pmÈ d]kÓ˜Uº=8@tÌüë”q?¦VÏÜÄ0/AàhÕu?Ÿ}ç/_rU®Ëoð #eïN¼%Y½]û^1û¾üÆ!yì§ïÞé].¹5+ä¹[„+ëÅœ¸ëî fm-ïAUjç¾³Ç%Š$f^¨Ñ¤c²…ãd÷"Ež‡Ûä×\Y\Ò—®êã²_þIMŸd¡îíëP¬,›¨‘w»Ø,ï³'c =FŸq?ª’¶ØçÎLH‚ÈùIÙp¥ü Y|ªPÑÞ•›ªíjïJ×¼)”]˜*§g2/å.ÎvÏÍ'ãU…·öVLéù‚®ôܼ¤Ð\þáQ"+ï%8#ô÷+Uêf1[§N£æ´‹Äƒ™,¬|íÌœž+††³YþH&¦M3:6~¶=> ÃPwíNS‚ô@{ŸËwšoEq!,d›wŽB%åvØØ8Q¹\É`'‰à8ÛfIèŽOšT*µ”)2²”Ëæt[tVLiµ³….·Ç‰ ]B¯Óg3[Là9€ùB¬ð7xA¥ÇC~­€…¸Ç£4ê“CÉ2ŠZê»ÚÂÀøX»ZEYku±\l¤E«m#:ؤ䘎’cíè0èZt:®ÎheqPLÉ2[N<)Ì,–I‰Úìf3ÂmÖ!bƒN+U·?cÍa˜rV©ÕÚæfm3쀕¶¾¾™+Ò1µLHפ²R©º^ËdrE­TÜ*00[À•ÛÔƒzµZÅÔ·…À?:\«”ªÊÞåõ!jz”ÒYzC*ÝJ”‘n£Þªªoh<Òt° ©¬fïþ ùîP{à`]Õ!Ð0ýž%®¬Ú³KìÝWU A„»õþÆåñЮQ!1v`²Ø»‡n÷_®rÔAIEND®B`‚libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/0000755000175000017500000000000012164627123022037 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/web.xml0000644000175000017500000000113411723544471023341 0ustar ebourgebourg FreeMarker Example Web Application 2 guestbook example.GuestbookServlet guestbook *.a help.html libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/templates/0000755000175000017500000000000012164627123024035 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/templates/add.ftl0000644000175000017500000000056411723544470025304 0ustar ebourgebourg<#import "/lib/common.ftl" as com> <#escape x as x?html> <@com.page title="Entry added">

You have added the following entry to the guestbook:

Name: ${entry.name} <#if entry.email?length != 0>

Email: ${entry.email}

Message: ${entry.message}

Back to the index page... libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/templates/form.ftl0000644000175000017500000000134111723544470025511 0ustar ebourgebourg<#import "/lib/common.ftl" as com> <#escape x as x?html> <@com.page title="Add Entry"> <#if errors?size != 0>

Please correct the following problems:

    <#list errors as e>
  • ${e}

Your name:

Your e-mail (optional):

Message:

Back to the index page libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/templates/index.ftl0000644000175000017500000000130511723544470025655 0ustar ebourgebourg<#import "/lib/common.ftl" as com> <#escape x as x?html> <@com.page title="Index"> Add new message | How this works? <#if guestbook?size = 0>

No messages. <#else>

The messages are:
Name Message <#list guestbook as e>
${e.name} <#if e.email?length != 0> (${e.email}) ${e.message}
libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/templates/lib/0000755000175000017500000000000012164627123024603 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/templates/lib/common.ftl0000644000175000017500000000111211723544471026601 0ustar ebourgebourg<#macro page title> FreeMarker Example Web Application 2 - ${title?html}

${title?html}


<#nested>
FreeMarker Example 2
libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/classes/0000755000175000017500000000000011723544467023505 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/classes/example/0000755000175000017500000000000012164627123025127 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/classes/example/Page.java0000644000175000017500000000170711723544470026656 0ustar ebourgebourgpackage example; import java.util.*; public class Page { private String template; private String forward; private Map root = new HashMap(); public String getTemplate() { return template; } public void setTemplate(String template) { forward = null; this.template = template; } public void put(String name, Object value) { root.put(name, value); } public void put(String name, int value) { root.put(name, new Integer(value)); } public void put(String name, double value) { root.put(name, new Double(value)); } public void put(String name, boolean value) { root.put(name, new Boolean(value)); } public Map getRoot() { return root; } public String getForward() { return forward; } public void setForward(String forward) { template = null; this.forward = forward; } } libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/classes/example/GuestbookEntry.java0000644000175000017500000000074011723544471030763 0ustar ebourgebourgpackage example; public class GuestbookEntry { private String name; private String email; private String message; public GuestbookEntry(String name, String email, String message) { this.name = name; this.email = email; this.message = message; } public String getEmail() { return email; } public String getMessage() { return message; } public String getName() { return name; } } libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/classes/example/ControllerServlet.java0000644000175000017500000001137211723544467031477 0ustar ebourgebourgpackage example; import java.io.*; import java.util.*; import java.lang.reflect.*; import javax.servlet.*; import javax.servlet.http.*; import freemarker.template.*; /** *

This is very very primitive MVC Controller servlet base class, based * on example 1. The application specific controller servlet should extend * this class. */ public class ControllerServlet extends HttpServlet { private Configuration cfg; public void init() { // Initialize the FreeMarker configuration; // - Create a configuration instance cfg = new Configuration(); // - Templates are stoted in the WEB-INF/templates directory of the Web app. cfg.setServletContextForTemplateLoading( getServletContext(), "WEB-INF/templates"); // - Set update dealy to 0 for now, to ease debugging and testing. // Higher value should be used in production environment. cfg.setTemplateUpdateDelay(0); // - Set an error handler that prints errors so they are readable with // a HTML browser. cfg.setTemplateExceptionHandler( TemplateExceptionHandler.HTML_DEBUG_HANDLER); // - Use beans wrapper (recommmended for most applications) cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER); // - Set the default charset of the template files cfg.setDefaultEncoding("ISO-8859-1"); // - Set the charset of the output. This is actually just a hint, that // templates may require for URL encoding and for generating META element // that uses http-equiv="Content-type". cfg.setOutputEncoding("UTF-8"); // - Set the default locale cfg.setLocale(Locale.US); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Choose action method String action = req.getServletPath(); if (action == null) action = "index"; if (action.startsWith("/")) action = action.substring(1); if (action.lastIndexOf(".") != -1) { action = action.substring(0, action.lastIndexOf(".")); } Method actionMethod; try { actionMethod = getClass().getMethod(action + "Action", new Class[]{HttpServletRequest.class, Page.class}); } catch (NoSuchMethodException e) { throw new ServletException("Unknown action: " + action); } // Set the request charset to the same as the output charset, // because HTML forms normally send parameters encoded with that. req.setCharacterEncoding(cfg.getOutputEncoding()); // Call the action method Page page = new Page(); try { actionMethod.invoke(this, new Object[]{req, page}); } catch (IllegalAccessException e) { throw new ServletException(e); } catch (InvocationTargetException e) { throw new ServletException(e.getTargetException()); } if (page.getTemplate() != null) { // show a page with a template // Get the template object Template t = cfg.getTemplate(page.getTemplate()); // Prepare the HTTP response: // - Set the MIME-type and the charset of the output. // Note that the charset should be in sync with the output_encoding setting. resp.setContentType("text/html; charset=" + cfg.getOutputEncoding()); // - Prevent browser or proxy caching the page. // Note that you should use it only for development and for interactive // pages, as it significantly slows down the Web site. resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, " + "post-check=0, pre-check=0"); resp.setHeader("Pragma", "no-cache"); resp.setHeader("Expires", "Thu, 01 Dec 1994 00:00:00 GMT"); Writer out = resp.getWriter(); // Merge the data-model and the template try { t.process(page.getRoot(), out); } catch (TemplateException e) { throw new ServletException( "Error while processing FreeMarker template", e); } } else if (page.getForward() != null) { // forward request RequestDispatcher rd = req.getRequestDispatcher(page.getForward()); rd.forward(req, resp); } else { throw new ServletException("The action didn't specified a command."); } } }libfreemarker-java-2.3.19.orig/examples/webapp2/WEB-INF/classes/example/GuestbookServlet.java0000644000175000017500000000470611723544470031313 0ustar ebourgebourgpackage example; import java.io.IOException; import java.util.*; import javax.servlet.ServletException; import javax.servlet.http.*; public class GuestbookServlet extends ControllerServlet { /** * Stores the list of guestbook entries. * *

Note that for the sake of simplicity, this example * does not try to store the guestbook persistenty. */ private ArrayList guestbook = new ArrayList(); public void indexAction(HttpServletRequest req, Page p) { List snapShot; synchronized (guestbook) { snapShot = (List) guestbook.clone(); } p.put("guestbook", snapShot); p.setTemplate("index.ftl"); } public void formAction (HttpServletRequest req, Page p) throws IOException, ServletException { p.put("name", noNull(req.getParameter("name"))); p.put("email", noNull(req.getParameter("email"))); p.put("message", noNull(req.getParameter("message"))); List errors = (List) req.getAttribute("errors"); p.put("errors", errors == null ? new ArrayList() : errors); p.setTemplate("form.ftl"); } public void addAction (HttpServletRequest req, Page p) throws IOException, ServletException { List errors = new ArrayList(); String name = req.getParameter("name"); String email = req.getParameter("email"); String message = req.getParameter("message"); if (isBlank(name)) { errors.add("You must give your name."); } if (isBlank(message)) { errors.add("You must give a message."); } // Was the sent data was correct? if (errors.isEmpty()) { if (email == null) email = ""; // Create and insert the new guestbook entry. GuestbookEntry e = new GuestbookEntry( name.trim(), email.trim(), message); synchronized (guestbook) { guestbook.add(0, e); } // Show "Entry added" page. p.put("entry", e); p.setTemplate("add.ftl"); } else { // Go back to the page of the form req.setAttribute("errors", errors); p.setForward("form.a"); } } public static String noNull(String s) { return s == null ? "" : s; } public static boolean isBlank(String s) { return s == null || s.trim().length() == 0; } } libfreemarker-java-2.3.19.orig/examples/webapp2/help.html0000644000175000017500000000570611723544472022643 0ustar ebourgebourg FreeMarker Example Web Application 2 - Help

FreeMarker Example Web Application 2

To try this example you should visit http://yourServer/thisWebApp/index.a

Note: To simplify the example, the guest-book entries are not stored persistently. If you reload the servlet all guest-book entry will lose.

What's this example about?

This is a very primitive controller servlet class (was written based on FreeMarker Example Web Application 1) and a simple guest-book appliction that uses the conroller servlet class. This whole stuff is a very primitive thing. It is only to get you started if you plan to develop some custom "framework" for your Web applications, rather than using an already written framework. Note that a Web application framework can use very different approach than this example.

How this example works?

This example uses a primitive controller servlet, example.ControllerServlet. To add application specific behavior, you should extend this servlet with an application specific subclass, that adds the so-called action methods. Here we implement a primitive guest book application by extending ControllerServlet with GuestbookServlet, that adds 3 action methods:

  • indexAction: Shows the whole guest-book.
  • formAction: Show the from where you enter a guest-book entry.
  • addAction: Adds a new guest-book entry.

The ControllerServlet calls the action methods when it receives client requests. It deduces the name of the action methods to call from the request URL. The servlet will be invoked only if the request URL is ending with ".a", as you can see in the WEB-INF/web.xml, otherwise a static file (for example this html file, or an image file) will be returned as is. To deduce the method name, the servlet removes the .a and the Web-application directory from the request URL, and then appends "Action". Thus, if you type http://yourServler/thisWebApp/foo.a, then it will try to call the fooAction method.

Each action method gets two parameters: the HttpServletRequest, and the Page object. The Page object plays the role of HttpServletResponse, but instead of calling low lever methods, you add objects to the data model with put(name, value), and choose the template (the view) with setTemplate(templateName); the tedious dirty work is done by ControllerServlet.

The templates are stored in the WEB-INF/templates directory.

For more details read the source code.


Back to the index page libfreemarker-java-2.3.19.orig/examples/ant/0000755000175000017500000000000012164627123020232 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/ant/faq2html.ftl0000644000175000017500000000221611723544467022471 0ustar ebourgebourg<#escape x as x?html> ${.node.faq.@title}

${.node.faq.@title}

<#noescape>${.node.faq.preface.@@markup}

Table of contents

<#list .node.faq.topicgroup as topicgroup>

${topicgroup.@name}

<#list topicgroup.topic as topic> ${topic.@name}

If your question was not answered by this FAQ, write to ${.node.faq.@adminName} (the current maintainer).

<#list .node.faq.topicgroup.topic as topic>

${topic.@name}

<#noescape>${topic.@@nested_markup}

Back to top

libfreemarker-java-2.3.19.orig/examples/ant/xml/0000755000175000017500000000000012164627123021032 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/ant/xml/faq.xml0000644000175000017500000002664611723544470022344 0ustar ebourgebourg

The easiest way is to use SimpleHash, SimpleList, and SimpleScalar. For example, suppose you want to be able to use a variable called foo.bar.baz.bing in your template. You could make a structure of nested SimpleHash objects like this:

SimpleHash foo = new SimpleHash();
SimpleHash bar = new SimpleHash();
SimpleHash baz = new SimpleHash();
SimpleScalar bing = new SimpleScalar("value of bing");
baz.put("bing", bing);
bar.put("baz", baz);
foo.put("bar", bar);
modelRoot.put("foo", foo);

What about nested lists? Suppose you wanted to write something like this in a template:

<list list1 as list2>
    <list list2 as list3>
        <list list3 as element>
            ${element}<br>
        </list>
    </list>
</list>

You could make nested SimpleLists like this:

SimpleList list1 = new SimpleList();
for (int i = 0; i < 3; i++) {
    SimpleList list2 = new SimpleList();
    for (int j = 0; j < 3; j++) {
        SimpleList list3 = new SimpleList();
        for (int k = 0; k < 3; k++) {
            list3.add(new SimpleScalar("test " +
                                       String.valueOf(i) +
                                       " " +
                                       String.valueOf(j) +
                                       " " +
                                       String.valueOf(k)));
        }
        list2.add(list3);
    }
    list1.add(list2);
}

modelRoot.put("list1", list1);

The template code above would then produce this output:

test 0 0 0
test 0 0 1
test 0 0 2
test 0 1 0
test 0 1 1
test 0 1 2
test 0 2 0
test 0 2 1
test 0 2 2
test 1 0 0
test 1 0 1
test 1 0 2
test 1 1 0

etc.

Yes, you can. In particular, you have to first build a JDOM tree from your XML document, and afterwards you can use JDOM tree nodes as data models. The extensions library has a class that can wrap a JDOM nodes to expose them to FreeMarker as a template model. In order to wrap your JDOM document tree in a freemarker TemplateModel, it is sufficient to do the following:

...
org.jdom.Document document = getMyDocumentSomehow(...);
TemplateModel model = new freemarker.ext.jdom.NodeListModel(document);
...
      

In the example below, the templates will be able to access the XML document through the "document" variable. The adapter supports all kinds of tree traversals and filterings, allows use of a node list as a TemplateListModel, and outputs XML fragments of contained nodes when used as a string literal. It also features full XPath support.

This FAQ page itself is created by applying a FreeMarker template to an XML document. Table of contents with links, topic grouping, and "Back to top" are all generated by the template. See the examples/jdom and examples/ant directories in FreeMarker distribution for example on using the XML support.

The extensions library has classes to wrap arbitrary Java objects as data models. In general, all you need to do to wrap your object obj into a TemplateModel is to call a single static factory method:

...
TemplateModel model = freemarker.ext.beans.ReflectionUtilities.wrap(obj);
...
      

After this, you can write arbitrary method calls on the wrapped object, i.e. you can write ${obj.getFoo()} in a template to execute method foo and place its result in the template output. Extensions library uses the JavaBeans introspector to discover available methods, so you can use bean property-style invocations as well: in previous example you could have written ${obj.foo} as well. If any property or method call returns an object, it is automatically wrapped for you, so you can chain invocations: {$obj.bar.baz.bing} would translate to what in Java would be obj.getBar().getBaz().getBing(). The framework automatically recognizes arrays as well as iterators, maps and collections from java.util package and provides them with additional capabilities (arrays, iterators, and collections act as list models and maps act as both lists of their entries and allow lookup when used as a method model). There is even a facility for invoking static methods (in case you ever needed System.currentTimeMillis() in a template).

It is worth noting that the framework caches the results of introspection, so that the negative performance impact resulting from reflected method lookup is minimized.

For example on using the reflection wrapper, see the examples/webapp directory in the FreeMarker distribution.

Yes, there is. The extensions library has the class freemarker.ext.servlet.FreemarkerServlet that you can use to provide template processing capabilities to your webapp. There is even a sample webapp under the examples/webapp directory of the distribution that should get you started.

In general, you should only place the following inside your web.xml file:

  <servlet>
    <servlet-name>freemarker</servlet-name>
    <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>
    <init-param>
      <param-name>TemplatePath</param-name>
      <param-value>/templates</param-value>
    </init-param>
    <init-param>
      <param-name>TemplateDelay</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>NoCache</param-name>
      <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>freemarker</servlet-name>
    <url-pattern>/templates/*</url-pattern>
  </servlet-mapping>

This will map all URLs beginning with /templates/ to templates in your webapp/templates directory. The servlet readily provides access to ServletContext, HttpSession, HttpServletRequest and HttpServletRequest parameters in the template data model. If you need to have additional variables available in your data model, just subclass the servlet and override the preTemplateProcess() method to shove any additional data you need into the model before the template gets processed.

Yes, you can. In particular, there is a FreeMarker task for Ant that will get a set of XML files, run them through a FreeMarker template, and output the resulting files in a target directory. This method is ideal for generating documentation, SQL scripts, or any other transformation requried during your build process. It is a viable alternative to Ant's xslt task. The Ant task is part of the extensions library. See the examples/ant directory in FreeMarker distribution for a sample build.xml file that employs FreeMarker.

Yes. As of 2.0, FreeMarker supports numerics without casting in and out of TemplateScalarModel. The new TemplateNumberModel intrace means that numbers of any given precision are supported, not just integers.

The basic arithmetic operators are supported, and meaningful comparison can be made between numbers. Internally, FreeMarker uses BigDecimals to ensure that no precision is lost when performing arithmetic operations. See the manual for further details.

I won't change the standard version, because a lot of templates depend on it. However, FreeMarker is designed to make it easy for you to change the syntax to suit your needs. Changing the tag delimiters, making tags case-insensitive, and representing operators differently would be simple changes to make. Take a look at freemarker.template.compiler.FMParser.jj, for more details. Let me know if you need further explanation of anything in the source code.

My view is that the editors that break template code are themselves broken; you'll probably have the same problem if you try to use them with other template systems. A good editor should ignore, not mangle, what it doesn't understand.

This isn't possible, because variable names can be dynamically generated from data (see the manual). However, there's a more important reason why FreeMarker doesn't support this. The design of FreeMarker is based on the idea of a separation between business objects and presentation objects. This separation takes two forms:

  1. The templates know what data to expect, but they don't know how it's generated.
  2. The business objects know what data to produce, but they don't know how it's going to be displayed. Therefore, they don't know anything about templates.

Since the business objects don't rely on the templates, if you need to use them with some other presentation system, you won't have to rewrite your application.

No. As of 2.0, FreeMarker is released under the BSD license. This means that source or binary distributions may be made freely, and can be included in other products, whether commercial or open source.

The only restrictions apply to the copyright of FreeMarker itself, and the use of FreeMarker or its contributors as endorsements of your own product. See the LICENSE for further details.

If you use FreeMarker, I hope you'll send me a link to some information about your product, but that's optional as well.

libfreemarker-java-2.3.19.orig/examples/ant/README.txt0000644000175000017500000000072511723544470021737 0ustar ebourgebourgBuilding the FAQ ================ Pre-requisites: * You'll need Ant installed on your machine, version 1.3 or later should work just fine. Ant can be downloaded from http://jakarta.apache.org/ant/ * You need jython.jar accessible in the classpath (or in the ant lib directory). (For no good reason anyway... I hope the author will fix it. Hello Mr. Authot?) Instructions: * Run Ant as you would do normally. The FAQ should appear in an html sub-directory. libfreemarker-java-2.3.19.orig/examples/ant/build.xml0000644000175000017500000000116511723544472022063 0ustar ebourgebourg libfreemarker-java-2.3.19.orig/examples/README.txt0000644000175000017500000000313211723544471021151 0ustar ebourgebourgExamples ======== Examples for FreeMarker (FM). Web application examples ------------------------ webapp1 Building Web app. framework around FM, step 1: Hello World! webapp2 Building Web app. framework around FM, step 2: Guest-book struts-webapp Using FM with Struts 1.1 Web app. framework: Guest-book jython-webapp Web app. that uses Jython instead of Java Language jsp-webapp Embedding FM templates into JSP pages In order not to duplicate too much JAR files around, we have not fully built the example webapps. To build the example webapps, you need Ant (http://ant.apache.org/) and run the following commands from the base FreeMarker directory: ant example- where is the name of the example as struts-webapp or webapp1. The built Web applications will be in the build/examples directory. You must create and edit dependencies.properties of the base FreeMarker directory, or the above will fail. An example of dependencies.properties: lib.servlet=/home/java/servlet/servlet2_3_jsp1_2.jar lib.struts=/home/java/strtus1_1/lib/struts.jar jython.home=/home/java/jython You need the lib.struts line only if you need the struts-webapp, and you need the jython.home line only if you need the jython-webapp. For more information please read the help.html or README.txt in the directory of examples. Especially, please read these files if the Web application does not show up after deployment. Note that you can build all Web applications using the single command: ant examples Other examples -------------- ant The FreeMarker XML transform Ant-tasklibfreemarker-java-2.3.19.orig/examples/struts-webapp/0000755000175000017500000000000012164627123022270 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/struts-webapp/add.ftl0000644000175000017500000000063111723544470023532 0ustar ebourgebourg<#import "/lib/common.ftl" as com> <#escape x as x?html> <@com.page title="Entry added">

You have added the following entry to the guestbook:

Name: ${guestbookEntry.name} <#if guestbookEntry.email?length != 0>

Email: ${guestbookEntry.email}

Message: ${guestbookEntry.message}

Back to the index page... libfreemarker-java-2.3.19.orig/examples/struts-webapp/form.ftl0000644000175000017500000000104611723544470023746 0ustar ebourgebourg<#import "/lib/common.ftl" as com> <#global html=JspTaglibs["/WEB-INF/struts-html.tld"]> <#escape x as x?html> <@com.page title="Add Entry"> <@html.errors/> <@html.form action="/add">

Your name:
<@html.text property="name" size="60"/>

Your e-mail (optional):
<@html.text property="email" size="60"/>

Message:
<@html.textarea property="message" rows="3" cols="60"/>

<@html.submit value="Submit"/>

Back to the index page libfreemarker-java-2.3.19.orig/examples/struts-webapp/poweredby_ffffff.png0000644000175000017500000000532711723544470026313 0ustar ebourgebourg‰PNG  IHDRXTúÒ,tEXtCreation TimeSzo 5 okt. 2002 00:01:59 +0100†*'tIMEÒ -5™ ì pHYs ð ðB¬4˜gAMA± üaPLTEÿÿÿùùùéééÞÞÞæææ÷÷÷ÓÓÓººº²²²¯¯¯¹¹¹ÑÑÑõõõïïïÈÈÈ———€€€}}}ŠŠŠ¨¨¨ÁÁÁýýýÊÊʈˆˆ™™™ÆÆÆ®®®ŽŽŽuuuvvv­­­ÎÎ΂‚‚äääÿÿÿþþþüüüÛÛÛqqqŒŒŒÉÉÉÌÌÌûûûúúúöööøøøôôô¶¶¶rrržžž“““±±±òòòðððñññîîîçççìììíííëëëãããáááóóóåååêêê‹‹‹ƒƒƒ„„„âââßßßÍÍÍÒÒÒÜÜÜÙÙÙÚÚÚàààÖÖÖÔÔÔèèèØØØÕÕÕ´´´«««ÝÝÝËË˽½½¼¼¼ÂÂÂÄÄÄÃÃÃÐÐÐÇÇÇÅÅÅ×××oooªªªeeeJJJ¸¸¸ÀÀÀÏÏÏkkk;;;RRR···UUU¿¿¿»»»¤¤¤DDDaaaPPPMMM¾¾¾ppp”””yyybbb¡¡¡§§§hhhµµµ‘‘‘’’’³³³¦¦¦777OOO¢¢¢œœœ```ŸŸŸTTT~~~SSS{{{555YYYiii   ¥¥¥GGG………‰‰‰xxx[[[nnnfff–––jjj@@@:::===©©©LLLZZZsssFFF£££ddd333<<<°°°VVVKKK¬¬¬QQQBBBEEE444888NNN111>>>›››\\\000666ccc|||---___,,,www]]]mmmlllzzz ???$$$///)))&&&•••"""(((ššš%%%999!!!XXX‡‡‡IIIWWW^^^†††gggÐ2vñtRNS@æØfIDATxÚ­–ý_S×Çóœ\’€J Š1 ¹!”ä’‡{IÔ<Ý<^’›1Hjxt©HI (P“8WµB±"ê6§m]Y[Y]WÛîyvvÝ¿³so€í‡ý²×xÿpÎù~Ïçûy}s’ss †¶§éÔ?oî¯k2Ê8šÎŸßlšMÕþÿÜ9÷ý‘¹ñÄ´/gâô÷¥x²aWÀÝùÆËç›D”ñ¥Ïg3¨ýçFÐdQ ÿüöŠÆ©4Q§±¹ëʈ(vf‘è¿Ä;"Q£±ÃØIífGÄôj[nk¯;(Ô2GÂr/M÷«WçÜd(÷Ý«`þGòÀª¤ð'õßµõðüGžˆí@òüêf¥&B^/þÍ•«'5=þë’Ü P‡¼Iɱ©0Î`¼¯‡Ë´mŒ~YLK43µóßö/NÝeâ/^¾|.æ§îòÓ±ÄV°üíä`õª>NÂ09þæäß«»2¿˜Œåã&çS+£. á].6-–  üû•”ÿÃZãâ݇ÅXïÃá?í¯ŽÝ®Íù}[ÁŸS‡÷,UóI¨»È¯[ GÿòY±8RÙà ¸ï ¦ £®/¡7¿øÝÆR*“]øråÑ|*º:%š½t( ?zñÕà…éèL¢PÌl'¾úbc²6Á¥ø‹¯Ï|st5Ÿù:µz('ÁáTc˜±ÙëÄ(œÏ5…êR»œ úÖGK‚¾¬,.Uz‰@"<»TìÍöF3®$±Ä×K«i—”:“}ë¥é¢|þ·¹° î`>çÃç”ñ‰Ú(ÐSd*JÜO6Z,t qB“‰Ê ÇМP–Å‘­@‘/æä¦uÅH1—pÏõ†{"À …>§³Aú÷ÄxòI`›§Èú1¥Ãã'ü‡‰Ã(²IÌáó8mÁí€Ò„T%Ëæº²! ‘ò6$‚ÚxÁmé °IÜDZ›í&Ôš¬‹=~÷0›l6e±X-vŽRi1UȲ¡6–……B‹N®SÆŸFÒa7±,o?{öìʱ‹Ð;FãèÇA»¹có7v»¥Ãh4"TîVÕÜ”÷(ç˜Ì”"ÎÑ‚·–ïLg'bè\®hð’N;²•,Ó:øi”m#?ýÌé nï´žF•fÿ5 ‘Nz¯•Ow¼×Ãm¡Ÿ ö_‘²„Üå ""î€||fC“üõí‹[,âꨜa-OàdG£{*0Z¹ÀL7B_Ž4kµZñüƒ ™ÝJþÒŸÈÈ2¯=aõ?¾ª1X÷Pc+ÿ~ÕÍ\j¬z@|òÁ‡báã¦'¼z S6Z1O<ø5p™ÍÌü)ÚØ'•újn_ˆØœ´¶¶v·¾VrÖ ùWç|û†Ø«s«ÿŠ{‡îÏCîÿY¢â½ ðA?_ÿE)pmÈ d]kÓ˜Uº=8@tÌüë”q?¦VÏÜÄ0/AàhÕu?Ÿ}ç/_rU®Ëoð #eïN¼%Y½]û^1û¾üÆ!yì§ïÞé].¹5+ä¹[„+ëÅœ¸ëî fm-ïAUjç¾³Ç%Š$f^¨Ñ¤c²…ãd÷"Ež‡Ûä×\Y\Ò—®êã²_þIMŸd¡îíëP¬,›¨‘w»Ø,ï³'c =FŸq?ª’¶ØçÎLH‚ÈùIÙp¥ü Y|ªPÑÞ•›ªíjïJ×¼)”]˜*§g2/å.ÎvÏÍ'ãU…·öVLéù‚®ôܼ¤Ð\þáQ"+ï%8#ô÷+Uêf1[§N£æ´‹Äƒ™,¬|íÌœž+††³YþH&¦M3:6~¶=> ÃPwíNS‚ô@{ŸËwšoEq!,d›wŽB%åvØØ8Q¹\É`'‰à8ÛfIèŽOšT*µ”)2²”Ëæt[tVLiµ³….·Ç‰ ]B¯Óg3[Là9€ùB¬ð7xA¥ÇC~­€…¸Ç£4ê“CÉ2ŠZê»ÚÂÀøX»ZEYku±\l¤E«m#:ؤ䘎’cíè0èZt:®ÎheqPLÉ2[N<)Ì,–I‰Úìf3ÂmÖ!bƒN+U·?cÍa˜rV©ÕÚæfm3쀕¶¾¾™+Ò1µLHפ²R©º^ËdrE­TÜ*00[À•ÛÔƒzµZÅÔ·…À?:\«”ªÊÞåõ!jz”ÒYzC*ÝJ”‘n£Þªªoh<Òt° ©¬fïþ ùîP{à`]Õ!Ð0ýž%®¬Ú³KìÝWU A„»õþÆåñЮQ!1v`²Ø»‡n÷_®rÔAIEND®B`‚libfreemarker-java-2.3.19.orig/examples/struts-webapp/index.ftl0000644000175000017500000000127011723544470024111 0ustar ebourgebourg<#import "/lib/common.ftl" as com> <#escape x as x?html> <@com.page title="Index"> Add new message | Help <#if guestbook?size = 0>

No messages. <#else>

The messages are:
Name Message <#list guestbook as e>
${e.name} <#if e.email?length != 0> (${e.email}) ${e.message}
libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/0000755000175000017500000000000012164627123023317 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/web.xml0000644000175000017500000000451211723544470024623 0ustar ebourgebourg FreeMarker Struts Example action example.GuestbookActionServlet config /WEB-INF/struts-config.xml debug 2 detail 2 2 freemarker freemarker.ext.servlet.FreemarkerServlet TemplatePath / NoCache true ContentType text/html template_update_delay 0 default_encoding ISO-8859-1 locale en_US number_format 0.########## 1 action *.do freemarker *.ftl help.html libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/struts-config.xml0000644000175000017500000000207711723544471026662 0ustar ebourgebourg libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/struts-html.tld0000644000175000017500000017106311723544470026345 0ustar ebourgebourg 1.0 1.1 html http://jakarta.apache.org/struts/tags-html-1.0 base org.apache.struts.taglib.html.BaseTag empty target false true button org.apache.struts.taglib.html.ButtonTag accesskey false true alt false true altKey false true disabled false true indexed false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true cancel org.apache.struts.taglib.html.CancelTag accesskey false true alt false true altKey false true disabled false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true checkbox org.apache.struts.taglib.html.CheckboxTag accesskey false true alt false true altKey false true disabled false true indexed false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true errors org.apache.struts.taglib.html.ErrorsTag empty bundle false true locale false true name false true property false true file org.apache.struts.taglib.html.FileTag accesskey false true accept false true alt false true altKey false true disabled false true indexed false true maxlength false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true size false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true form org.apache.struts.taglib.html.FormTag JSP action true true enctype false true focus false true method false true name false true onreset false true onsubmit false true scope false true style false true styleClass false true styleId false true target false true type false true frame org.apache.struts.taglib.html.FrameTag anchor false true forward false true frameborder false true frameName false true href false true longdesc false true marginheight false true marginwidth false true name false true noresize false true page false true paramId false true paramName false true paramProperty false true paramScope false true property false true scope false true scrolling false true style false true styleClass false true styleId false true title false true titleKey false true transaction false true hidden org.apache.struts.taglib.html.HiddenTag accesskey false true alt false true altKey false true indexed false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true style false true styleClass false true styleId false true title false true titleKey false true value false true write false true html org.apache.struts.taglib.html.HtmlTag JSP locale false true xhtml false true image org.apache.struts.taglib.html.ImageTag accesskey false true align false true alt false true altKey false true border false true bundle false true disabled false true indexed false true locale false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true page false true pageKey false true property false true src false true srcKey false true style false true styleClass false true tabindex false true title false true titleKey false true value false true img org.apache.struts.taglib.html.ImgTag empty accesskey false true align false true alt false true altKey false true border false true bundle false true height false true hspace false true imageName false true ismap false true locale false true lowsrc false true name false true onclick false true ondblclick false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true paramId false true page false true pageKey false true paramName false true paramProperty false true paramScope false true property false true scope false true src false true srcKey false true style false true styleClass false true styleId false true title false true titleKey false true usemap false true vspace false true width false true javascript org.apache.struts.taglib.html.JavascriptValidatorTag empty dynamicJavascript false false formName false true method false true page false true src false true staticJavascript false false link org.apache.struts.taglib.html.LinkTag accesskey false true anchor false true forward false true href false true indexed false true indexId false true linkName false true name false true onblur false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true page false true paramId false true paramName false true paramProperty false true paramScope false true property false true scope false true style false true styleClass false true styleId false true tabindex false true target false true title false true titleKey false true transaction false true messages org.apache.struts.taglib.html.MessagesTag org.apache.struts.taglib.html.MessagesTei JSP id true true bundle false true locale false true name false true property false true header false true footer false true message false true multibox org.apache.struts.taglib.html.MultiboxTag accesskey false true alt false true altKey false true disabled false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true option org.apache.struts.taglib.html.OptionTag bundle false true disabled false true key false true locale false true style false true styleClass false true value true true options org.apache.struts.taglib.html.OptionsTag empty collection false true filter false true labelName false true labelProperty false true name false true property false true style false true styleClass false true optionsCollection org.apache.struts.taglib.html.OptionsCollectionTag empty filter false true label false true name false true property true true style false true styleClass false true value false true password org.apache.struts.taglib.html.PasswordTag accesskey false true alt false true altKey false true disabled false true indexed false true maxlength false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true readonly false true redisplay false true style false true styleClass false true styleId false true size false true tabindex false true title false true titleKey false true value false true radio org.apache.struts.taglib.html.RadioTag accesskey false true alt false true altKey false true disabled false true indexed false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true property true true onmousedown false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value true true idName false true reset org.apache.struts.taglib.html.ResetTag accesskey false true alt false true altKey false true disabled false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true rewrite org.apache.struts.taglib.html.RewriteTag empty anchor false true forward false true href false true name false true page false true paramId false true paramName false true paramProperty false true paramScope false true property false true scope false true transaction false true select org.apache.struts.taglib.html.SelectTag JSP accesskey false true alt false true altKey false true disabled false true indexed false true multiple false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true style false true styleClass false true styleId false true tabindex false true size false true title false true titleKey false true value false true submit org.apache.struts.taglib.html.SubmitTag accesskey false true alt false true altKey false true disabled false true indexed false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true text org.apache.struts.taglib.html.TextTag accesskey false true alt false true altKey false true disabled false true indexed false true maxlength false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true readonly false true size false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true textarea org.apache.struts.taglib.html.TextareaTag accesskey false true alt false true altKey false true cols false true disabled false true indexed false true name false true onblur false true onchange false true onclick false true ondblclick false true onfocus false true onkeydown false true onkeypress false true onkeyup false true onmousedown false true onmousemove false true onmouseout false true onmouseover false true onmouseup false true property true true readonly false true rows false true style false true styleClass false true styleId false true tabindex false true title false true titleKey false true value false true libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/0000755000175000017500000000000011723544467024765 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/0000755000175000017500000000000012164627123026407 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/FormAction.java0000644000175000017500000000057711723544470031327 0ustar ebourgebourgpackage example; import javax.servlet.http.*; import org.apache.struts.action.*; public class FormAction extends GuestbookAction { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse resp) throws Exception { return mapping.findForward("success"); } } libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/IndexAction.java0000644000175000017500000000112311723544470031457 0ustar ebourgebourgpackage example; import java.util.*; import javax.servlet.http.*; import org.apache.struts.action.*; public class IndexAction extends GuestbookAction { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse resp) throws Exception { List snapShot; synchronized (getGuestbook()) { snapShot = (List) getGuestbook().clone(); } req.setAttribute("guestbook", snapShot); return mapping.findForward("success"); } } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootlibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/GuestbookActionServlet.javalibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/GuestbookActionServlet0000644000175000017500000000101011723544471032773 0ustar ebourgebourgpackage example; import java.util.*; import javax.servlet.*; import org.apache.struts.action.ActionServlet; public class GuestbookActionServlet extends ActionServlet { static final String GUESTBOOK_KEY = "guestbook"; public void init(ServletConfig scfg) throws ServletException { super.init(scfg); ServletContext sctx = scfg.getServletContext(); // Add application specific global objects sctx.setAttribute(GUESTBOOK_KEY, new ArrayList()); } } libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/GuestbookEntry.java0000644000175000017500000000073411723544471032246 0ustar ebourgebourgpackage example; public class GuestbookEntry { private String name; private String email; private String message; public GuestbookEntry(String name, String email, String message) { this.name = name; this.email = email; this.message = message; } public String getEmail() { return email; } public String getMessage() { return message; } public String getName() { return name; } } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootlibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/ApplicationResources.propertieslibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/ApplicationResources.p0000644000175000017500000000030111723544471032724 0ustar ebourgebourgerrors.header=

Please correct the following problems:

    errors.prefix=
  • errors.suffix= errors.footer=
errors.required={0} is required. libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/AddAction.java0000644000175000017500000000124011723544467031106 0ustar ebourgebourgpackage example; import java.util.List; import javax.servlet.http.*; import org.apache.struts.action.*; public class AddAction extends GuestbookAction { public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse resp) throws Exception { GuestbookEntryForm f = (GuestbookEntryForm) form; List guestbook = getGuestbook(); synchronized (guestbook) { guestbook.add(0, new GuestbookEntry( f.getName(), f.getEmail(), f.getMessage())); } return mapping.findForward("success"); } } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootlibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/GuestbookEntryForm.javalibfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/GuestbookEntryForm.jav0000644000175000017500000000242311723544467032733 0ustar ebourgebourgpackage example; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.*; public class GuestbookEntryForm extends ActionForm { private String name; private String email; private String message; public GuestbookEntryForm() { } public String getEmail() { return email; } public void setEmail(String email) { this.email = normalizeString(email); } public String getMessage() { return message; } public void setMessage(String message) { this.message = normalizeString(message); } public void setName(String name) { this.name = normalizeString(name); } public String getName() { return name; } public ActionErrors validate(ActionMapping arg0, HttpServletRequest arg1) { ActionErrors errs = new ActionErrors(); if (name.length() == 0) { errs.add("name", new ActionError("errors.required", "name")); } if (message.length() == 0) { errs.add("message", new ActionError("errors.required", "message")); } return errs.size() == 0 ? null : errs; } private static String normalizeString(String s) { if (s == null) return ""; return s.trim(); } }libfreemarker-java-2.3.19.orig/examples/struts-webapp/WEB-INF/classes/example/GuestbookAction.java0000644000175000017500000000053211723544470032355 0ustar ebourgebourgpackage example; import java.util.*; import org.apache.struts.action.*; /** * Defines utility methods for this application. */ public class GuestbookAction extends Action { ArrayList getGuestbook() { return (ArrayList) servlet.getServletContext() .getAttribute(GuestbookActionServlet.GUESTBOOK_KEY); } } libfreemarker-java-2.3.19.orig/examples/struts-webapp/lib/0000755000175000017500000000000012164627123023036 5ustar ebourgebourglibfreemarker-java-2.3.19.orig/examples/struts-webapp/lib/common.ftl0000644000175000017500000000107311723544471025042 0ustar ebourgebourg<#macro page title> FreeMarker Struts Example - ${title?html}

${title?html}


<#nested>
FreeMarker Struts Example
libfreemarker-java-2.3.19.orig/examples/struts-webapp/help.html0000644000175000017500000000233011723544472024111 0ustar ebourgebourg FreeMarker Struts Example - Help

FreeMarker Struts Example

This is an example of using FreeMarker templates instead of JSP with Struts 1.1. You can find more information about FreeMarker and "Model 2" applications in the FreeMarker Manual.

Before deploying this Web application, you must copy the .jar files that are commonly required for Struts applications (sruts.jar, common-...jar-s) into the WEB-INF/lib directory manually, or the Web application will not start. You may find these files in the lib directory of the Struts distribution, or in the WEB-INF/lib directory of examples comes with the Struts distribution. (The FreeMarker distribution does not contain these files since they are too big.)

To try this example you should visit http://yourServer/thisWebApp/index.do

Note: To simplify the example, the guest-book entries are not stored persistently. If you reload the servlet all guest-book entry will lose.


Back to the index page libfreemarker-java-2.3.19.orig/NOTICE.txt0000644000175000017500000000021611723544471017357 0ustar ebourgebourgThis product includes software developed by The Apache Software Foundation (http://www.apache.org/). See the LICENSE.txt for more details.libfreemarker-java-2.3.19.orig/build.xml0000644000175000017500000014065311723544470017467 0ustar ebourgebourg Fetching libraries from server. 4.0.0 org.freemarker freemarker ${version} jar FreeMarker FreeMarker is a "template engine"; a generic tool to generate text output based on templates. http://freemarker.org BSD-style license http://freemarker.org/LICENSE.txt http://freemarker.svn.sourceforge.net/viewvc/freemarker/ scm:svn:https://freemarker.svn.sourceforge.net/svnroot/freemarker ]]> You are about uploading ${dist.dir.versioned}/lib/freemarker.jar into the Maven central repostiry sync. directory. Be sure that's the final (released) variation there, and that the version number is correct. Proceed? ********************************************** CLEAR THE SCREEN, NOW! Your password is on it! **********************************************