All Downloads are FREE. Search and download functionalities are using the official Maven repository.

freemarker.template.Configuration Maven / Gradle / Ivy

There is a newer version: 0.4.3
Show newest version
/*
 * 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 [email protected].
 *
 * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
 *    nor may "FreeMarker" or "Visigoth" appear in their names
 *    without prior written permission of the Visigoth Software Society.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made 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.*;
import java.util.*;

import freemarker.cache.*;
import freemarker.core.*;
import freemarker.template.utility.*;

/**
 * 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 int AUTO_DETECT_TAG_SYNTAX = 0;
    public static final int ANGLE_BRACKET_TAG_SYNTAX = 1;
    public static final int SQUARE_BRACKET_TAG_SYNTAX = 2;


    private static Configuration defaultConfig = new Configuration();
    private static String cachedVersion;
    private boolean strictSyntax = true, localizedLookup = true, whitespaceStripping = true;
    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(); } 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 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; } /** * @return whether the alternative square bracket * syntax is set as the default */ 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(); } /** * 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. * See also: {@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". *
* * @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; } 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(new SettingStringParser(value).parseAsList()); } else if (AUTO_IMPORT_KEY.equals(key)) { setAutoImports(new SettingStringParser(value).parseAsImportList()); } 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 { super.setSetting(key, value); } } catch(Exception e) { throw new TemplateException( "Failed to set setting " + key + " to value " + value, e, getEnvironment()); } } /** * 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); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy