http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/template/Configuration.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/template/Configuration.java b/src/main/java/freemarker/template/Configuration.java deleted file mode 100644 index b2f9b0e..0000000 --- a/src/main/java/freemarker/template/Configuration.java +++ /dev/null @@ -1,3189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package freemarker.template; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLConnection; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import freemarker.cache.CacheStorage; -import freemarker.cache.ClassTemplateLoader; -import freemarker.cache.FileTemplateLoader; -import freemarker.cache.MruCacheStorage; -import freemarker.cache.MultiTemplateLoader; -import freemarker.cache.SoftCacheStorage; -import freemarker.cache.TemplateCache; -import freemarker.cache.TemplateCache.MaybeMissingTemplate; -import freemarker.cache.TemplateConfigurationFactory; -import freemarker.cache.TemplateLoader; -import freemarker.cache.TemplateLookupContext; -import freemarker.cache.TemplateLookupStrategy; -import freemarker.cache.TemplateNameFormat; -import freemarker.cache.URLTemplateLoader; -import freemarker.core.BugException; -import freemarker.core.CSSOutputFormat; -import freemarker.core.CombinedMarkupOutputFormat; -import freemarker.core.Configurable; -import freemarker.core.Environment; -import freemarker.core.HTMLOutputFormat; -import freemarker.core.JSONOutputFormat; -import freemarker.core.JavaScriptOutputFormat; -import freemarker.core.MarkupOutputFormat; -import freemarker.core.OutputFormat; -import freemarker.core.ParseException; -import freemarker.core.ParserConfiguration; -import freemarker.core.PlainTextOutputFormat; -import freemarker.core.RTFOutputFormat; -import freemarker.core.TemplateConfiguration; -import freemarker.core.TemplateMarkupOutputModel; -import freemarker.core.UndefinedOutputFormat; -import freemarker.core.UnregisteredOutputFormatException; -import freemarker.core.XHTMLOutputFormat; -import freemarker.core.XMLOutputFormat; -import freemarker.core._CoreAPI; -import freemarker.core._DelayedJQuote; -import freemarker.core._MiscTemplateException; -import freemarker.core._ObjectBuilderSettingEvaluator; -import freemarker.core._SettingEvaluationEnvironment; -import freemarker.core._SortedArraySet; -import freemarker.core._UnmodifiableCompositeSet; -import freemarker.ext.beans.BeansWrapper; -import freemarker.ext.beans.BeansWrapperBuilder; -import freemarker.template.utility.CaptureOutput; -import freemarker.template.utility.ClassUtil; -import freemarker.template.utility.Constants; -import freemarker.template.utility.HtmlEscape; -import freemarker.template.utility.NormalizeNewlines; -import freemarker.template.utility.NullArgumentException; -import freemarker.template.utility.SecurityUtilities; -import freemarker.template.utility.StandardCompress; -import freemarker.template.utility.StringUtil; -import freemarker.template.utility.XmlEscape; - -/** - * <b>The main entry point into the FreeMarker API</b>; encapsulates the configuration settings of FreeMarker, - * also serves as a central template-loading and caching service. - * - * <p>This class is meant to be used in a singleton pattern. That is, you create an instance of this at the beginning of - * the application life-cycle, set its {@link #setSetting(String, String) configuration settings} there (either with the - * setter methods like {@link #setTemplateLoader(TemplateLoader)} or by loading a {@code .properties} file), and then - * use that single instance everywhere in your application. Frequently re-creating {@link Configuration} is a typical - * and grave mistake from performance standpoint, as the {@link Configuration} holds the template cache, and often also - * the class introspection cache, which then will be lost. (Note that, naturally, having multiple long-lived instances, - * like one per component that internally uses FreeMarker is fine.) - * - * <p>The basic usage pattern is like: - * - * <pre> - * // Where the application is initialized; in general you do this ONLY ONCE in the application life-cycle! - * Configuration cfg = new Configuration(VERSION_<i>X</i>_<i>Y</i>_<i>Z</i>)); - * // Where X, Y, Z enables the not-100%-backward-compatible fixes introduced in - * // FreeMarker version X.Y.Z and earlier (see {@link #Configuration(Version)}). - * cfg.set<i>SomeSetting</i>(...); - * cfg.set<i>OtherSetting</i>(...); - * ... - * - * // Later, whenever the application needs a template (so you may do this a lot, and from multiple threads): - * {@link Template Template} myTemplate = cfg.{@link #getTemplate(String) getTemplate}("myTemplate.html"); - * myTemplate.{@link Template#process(Object, java.io.Writer) process}(dataModel, out);</pre> - * - * <p>A couple of settings that you should not leave on its default value are: - * <ul> - * <li>{@link #setTemplateLoader(TemplateLoader) template_loader}: The default value is deprecated and in fact quite - * useless. (For the most common cases you can use the convenience methods, - * {@link #setDirectoryForTemplateLoading(File)} and {@link #setClassForTemplateLoading(Class, String)} and - * {@link #setClassLoaderForTemplateLoading(ClassLoader, String)} too.) - * <li>{@link #setDefaultEncoding(String) default_encoding}: The default value is system dependent, which makes it - * fragile on servers, so it should be set explicitly, like to "UTF-8" nowadays. - * <li>{@link #setTemplateExceptionHandler(TemplateExceptionHandler) template_exception_handler}: For developing - * HTML pages, the most convenient value is {@link TemplateExceptionHandler#HTML_DEBUG_HANDLER}. For production, - * {@link TemplateExceptionHandler#RETHROW_HANDLER} is safer to use. - * <!-- 2.4: recommend the new object wrapper here --> - * </ul> - * - * <p>A {@link Configuration} object is thread-safe only after you have stopped modifying the configuration settings, - * and you have <b>safely published</b> it (see JSR 133 and related literature) to other threads. Generally, you set - * everything directly after you have instantiated the {@link Configuration} object, then you don't change the settings - * anymore, so then it's safe to make it accessible (again, via a "safe publication" technique) from multiple threads. - * The methods that aren't for modifying settings, like {@link #getTemplate(String)}, are thread-safe. - */ -public class Configuration extends Configurable implements Cloneable, ParserConfiguration { - - private static final Logger LOG = LoggerFactory.getLogger("freemarker.cache"); - - private static final String VERSION_PROPERTIES_PATH = "freemarker/version.properties"; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String DEFAULT_ENCODING_KEY_SNAKE_CASE = "default_encoding"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String DEFAULT_ENCODING_KEY_CAMEL_CASE = "defaultEncoding"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String DEFAULT_ENCODING_KEY = DEFAULT_ENCODING_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String LOCALIZED_LOOKUP_KEY_SNAKE_CASE = "localized_lookup"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String LOCALIZED_LOOKUP_KEY_CAMEL_CASE = "localizedLookup"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String LOCALIZED_LOOKUP_KEY = LOCALIZED_LOOKUP_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String WHITESPACE_STRIPPING_KEY_SNAKE_CASE = "whitespace_stripping"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String WHITESPACE_STRIPPING_KEY_CAMEL_CASE = "whitespaceStripping"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String WHITESPACE_STRIPPING_KEY = WHITESPACE_STRIPPING_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.24 */ - public static final String OUTPUT_FORMAT_KEY_SNAKE_CASE = "output_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.24 */ - public static final String OUTPUT_FORMAT_KEY_CAMEL_CASE = "outputFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String OUTPUT_FORMAT_KEY = OUTPUT_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.24 */ - public static final String RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_SNAKE_CASE = "recognize_standard_file_extensions"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.24 */ - public static final String RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_CAMEL_CASE = "recognizeStandardFileExtensions"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY - = RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.24 */ - public static final String REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_SNAKE_CASE = "registered_custom_output_formats"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.24 */ - public static final String REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_CAMEL_CASE = "registeredCustomOutputFormats"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY = REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.24 */ - public static final String AUTO_ESCAPING_POLICY_KEY_SNAKE_CASE = "auto_escaping_policy"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.24 */ - public static final String AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE = "autoEscapingPolicy"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String AUTO_ESCAPING_POLICY_KEY = AUTO_ESCAPING_POLICY_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String CACHE_STORAGE_KEY_SNAKE_CASE = "cache_storage"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String CACHE_STORAGE_KEY_CAMEL_CASE = "cacheStorage"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String CACHE_STORAGE_KEY = CACHE_STORAGE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_UPDATE_DELAY_KEY_SNAKE_CASE = "template_update_delay"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_UPDATE_DELAY_KEY_CAMEL_CASE = "templateUpdateDelay"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TEMPLATE_UPDATE_DELAY_KEY = TEMPLATE_UPDATE_DELAY_KEY_SNAKE_CASE; - - /** - * Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 - * @deprecated Use {@link Configurable#AUTO_IMPORT_KEY_SNAKE_CASE} instead. - */ - @Deprecated - public static final String AUTO_IMPORT_KEY_SNAKE_CASE = "auto_import"; - /** - * Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 - * @deprecated Use {@link Configurable#AUTO_IMPORT_KEY_CAMEL_CASE} instead. - */ - @Deprecated - public static final String AUTO_IMPORT_KEY_CAMEL_CASE = "autoImport"; - /** - * Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. - * @deprecated Use {@link Configurable#AUTO_IMPORT_KEY_SNAKE_CASE} instead. - */ - @Deprecated - public static final String AUTO_IMPORT_KEY = AUTO_IMPORT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String AUTO_INCLUDE_KEY_SNAKE_CASE = "auto_include"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String AUTO_INCLUDE_KEY_CAMEL_CASE = "autoInclude"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String AUTO_INCLUDE_KEY = AUTO_INCLUDE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TAG_SYNTAX_KEY_SNAKE_CASE = "tag_syntax"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TAG_SYNTAX_KEY_CAMEL_CASE = "tagSyntax"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TAG_SYNTAX_KEY = TAG_SYNTAX_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String NAMING_CONVENTION_KEY_SNAKE_CASE = "naming_convention"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String NAMING_CONVENTION_KEY_CAMEL_CASE = "namingConvention"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String NAMING_CONVENTION_KEY = NAMING_CONVENTION_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.25 */ - public static final String TAB_SIZE_KEY_SNAKE_CASE = "tab_size"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.25 */ - public static final String TAB_SIZE_KEY_CAMEL_CASE = "tabSize"; - /** Alias to the {@code ..._SNAKE_CASE} variation. @since 2.3.25 */ - public static final String TAB_SIZE_KEY = TAB_SIZE_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_LOADER_KEY_SNAKE_CASE = "template_loader"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_LOADER_KEY_CAMEL_CASE = "templateLoader"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TEMPLATE_LOADER_KEY = TEMPLATE_LOADER_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_LOOKUP_STRATEGY_KEY_SNAKE_CASE = "template_lookup_strategy"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_LOOKUP_STRATEGY_KEY_CAMEL_CASE = "templateLookupStrategy"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TEMPLATE_LOOKUP_STRATEGY_KEY = TEMPLATE_LOOKUP_STRATEGY_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_NAME_FORMAT_KEY_SNAKE_CASE = "template_name_format"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String TEMPLATE_NAME_FORMAT_KEY_CAMEL_CASE = "templateNameFormat"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String TEMPLATE_NAME_FORMAT_KEY = TEMPLATE_NAME_FORMAT_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.24 */ - public static final String TEMPLATE_CONFIGURATIONS_KEY_SNAKE_CASE = "template_configurations"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.24 */ - public static final String TEMPLATE_CONFIGURATIONS_KEY_CAMEL_CASE = "templateConfigurations"; - /** Alias to the {@code ..._SNAKE_CASE} variation. @since 2.3.24 */ - public static final String TEMPLATE_CONFIGURATIONS_KEY = TEMPLATE_CONFIGURATIONS_KEY_SNAKE_CASE; - - /** Legacy, snake case ({@code like_this}) variation of the setting name. @since 2.3.23 */ - public static final String INCOMPATIBLE_IMPROVEMENTS_KEY_SNAKE_CASE = "incompatible_improvements"; - /** Modern, camel case ({@code likeThis}) variation of the setting name. @since 2.3.23 */ - public static final String INCOMPATIBLE_IMPROVEMENTS_KEY_CAMEL_CASE = "incompatibleImprovements"; - /** Alias to the {@code ..._SNAKE_CASE} variation due to backward compatibility constraints. */ - public static final String INCOMPATIBLE_IMPROVEMENTS_KEY = INCOMPATIBLE_IMPROVEMENTS_KEY_SNAKE_CASE; - - /** @deprecated Use {@link #INCOMPATIBLE_IMPROVEMENTS_KEY} instead. */ - @Deprecated - public static final String INCOMPATIBLE_IMPROVEMENTS = INCOMPATIBLE_IMPROVEMENTS_KEY_SNAKE_CASE; - /** @deprecated Use {@link #INCOMPATIBLE_IMPROVEMENTS_KEY} instead. */ - @Deprecated - public static final String INCOMPATIBLE_ENHANCEMENTS = "incompatible_enhancements"; - - private static final String[] SETTING_NAMES_SNAKE_CASE = new String[] { - // Must be sorted alphabetically! - AUTO_ESCAPING_POLICY_KEY_SNAKE_CASE, - CACHE_STORAGE_KEY_SNAKE_CASE, - DEFAULT_ENCODING_KEY_SNAKE_CASE, - INCOMPATIBLE_IMPROVEMENTS_KEY_SNAKE_CASE, - LOCALIZED_LOOKUP_KEY_SNAKE_CASE, - NAMING_CONVENTION_KEY_SNAKE_CASE, - OUTPUT_FORMAT_KEY_SNAKE_CASE, - RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_SNAKE_CASE, - REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_SNAKE_CASE, - TAB_SIZE_KEY_SNAKE_CASE, - TAG_SYNTAX_KEY_SNAKE_CASE, - TEMPLATE_CONFIGURATIONS_KEY_SNAKE_CASE, - TEMPLATE_LOADER_KEY_SNAKE_CASE, - TEMPLATE_LOOKUP_STRATEGY_KEY_SNAKE_CASE, - TEMPLATE_NAME_FORMAT_KEY_SNAKE_CASE, - TEMPLATE_UPDATE_DELAY_KEY_SNAKE_CASE, - WHITESPACE_STRIPPING_KEY_SNAKE_CASE, - }; - - private static final String[] SETTING_NAMES_CAMEL_CASE = new String[] { - // Must be sorted alphabetically! - AUTO_ESCAPING_POLICY_KEY_CAMEL_CASE, - CACHE_STORAGE_KEY_CAMEL_CASE, - DEFAULT_ENCODING_KEY_CAMEL_CASE, - INCOMPATIBLE_IMPROVEMENTS_KEY_CAMEL_CASE, - LOCALIZED_LOOKUP_KEY_CAMEL_CASE, - NAMING_CONVENTION_KEY_CAMEL_CASE, - OUTPUT_FORMAT_KEY_CAMEL_CASE, - RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY_CAMEL_CASE, - REGISTERED_CUSTOM_OUTPUT_FORMATS_KEY_CAMEL_CASE, - TAB_SIZE_KEY_CAMEL_CASE, - TAG_SYNTAX_KEY_CAMEL_CASE, - TEMPLATE_CONFIGURATIONS_KEY_CAMEL_CASE, - TEMPLATE_LOADER_KEY_CAMEL_CASE, - TEMPLATE_LOOKUP_STRATEGY_KEY_CAMEL_CASE, - TEMPLATE_NAME_FORMAT_KEY_CAMEL_CASE, - TEMPLATE_UPDATE_DELAY_KEY_CAMEL_CASE, - WHITESPACE_STRIPPING_KEY_CAMEL_CASE - }; - - private static final Map<String, OutputFormat> STANDARD_OUTPUT_FORMATS; - static { - STANDARD_OUTPUT_FORMATS = new HashMap<String, OutputFormat>(); - STANDARD_OUTPUT_FORMATS.put(UndefinedOutputFormat.INSTANCE.getName(), UndefinedOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(HTMLOutputFormat.INSTANCE.getName(), HTMLOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(XHTMLOutputFormat.INSTANCE.getName(), XHTMLOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(XMLOutputFormat.INSTANCE.getName(), XMLOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(RTFOutputFormat.INSTANCE.getName(), RTFOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(PlainTextOutputFormat.INSTANCE.getName(), PlainTextOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(CSSOutputFormat.INSTANCE.getName(), CSSOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(JavaScriptOutputFormat.INSTANCE.getName(), JavaScriptOutputFormat.INSTANCE); - STANDARD_OUTPUT_FORMATS.put(JSONOutputFormat.INSTANCE.getName(), JSONOutputFormat.INSTANCE); - } - - 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 int AUTO_DETECT_NAMING_CONVENTION = 10; - public static final int LEGACY_NAMING_CONVENTION = 11; - public static final int CAMEL_CASE_NAMING_CONVENTION = 12; - - /** - * Don't enable auto-escaping, regardless of what the {@link OutputFormat} is. Note that a {@code - * <#ftl auto_esc=true>} in the template will override this. - */ - public static final int DISABLE_AUTO_ESCAPING_POLICY = 20; - /** - * Enable auto-escaping if the output format supports it and {@link MarkupOutputFormat#isAutoEscapedByDefault()} is - * {@code true}. - */ - public static final int ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY = 21; - /** Enable auto-escaping if the {@link OutputFormat} supports it. */ - public static final int ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY = 22; - - /** FreeMarker version 2.3.0 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_0 = new Version(2, 3, 0); - - /** FreeMarker version 2.3.19 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_19 = new Version(2, 3, 19); - - /** FreeMarker version 2.3.20 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_20 = new Version(2, 3, 20); - - /** FreeMarker version 2.3.21 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_21 = new Version(2, 3, 21); - - /** FreeMarker version 2.3.22 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_22 = new Version(2, 3, 22); - - /** FreeMarker version 2.3.23 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_23 = new Version(2, 3, 23); - - /** FreeMarker version 2.3.24 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_24 = new Version(2, 3, 24); - - /** FreeMarker version 2.3.25 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_25 = new Version(2, 3, 25); - - /** FreeMarker version 2.3.26 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_2_3_26 = new Version(2, 3, 26); - - /** FreeMarker version 3.0.0 (an {@link #Configuration(Version) incompatible improvements break-point}) */ - public static final Version VERSION_3_0_0 = new Version(3, 0, 0); - - /** The default of {@link #getIncompatibleImprovements()}, currently {@link #VERSION_2_3_0}. */ - public static final Version DEFAULT_INCOMPATIBLE_IMPROVEMENTS = Configuration.VERSION_2_3_0; - /** @deprecated Use {@link #DEFAULT_INCOMPATIBLE_IMPROVEMENTS} instead. */ - @Deprecated - public static final String DEFAULT_INCOMPATIBLE_ENHANCEMENTS = DEFAULT_INCOMPATIBLE_IMPROVEMENTS.toString(); - /** @deprecated Use {@link #DEFAULT_INCOMPATIBLE_IMPROVEMENTS} instead. */ - @Deprecated - public static final int PARSED_DEFAULT_INCOMPATIBLE_ENHANCEMENTS = DEFAULT_INCOMPATIBLE_IMPROVEMENTS.intValue(); - - private static final String NULL = "null"; - private static final String DEFAULT = "default"; - - private static final Version VERSION; - static { - try { - Properties vp = new Properties(); - InputStream ins = Configuration.class.getClassLoader() - .getResourceAsStream(VERSION_PROPERTIES_PATH); - if (ins == null) { - throw new RuntimeException("Version file is missing."); - } else { - try { - vp.load(ins); - } finally { - ins.close(); - } - - String versionString = getRequiredVersionProperty(vp, "version"); - - Date buildDate; - { - String buildDateStr = getRequiredVersionProperty(vp, "buildTimestamp"); - if (buildDateStr.endsWith("Z")) { - buildDateStr = buildDateStr.substring(0, buildDateStr.length() - 1) + "+0000"; - } - try { - buildDate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US).parse(buildDateStr); - } catch (java.text.ParseException e) { - buildDate = null; - } - } - - final Boolean gaeCompliant = Boolean.valueOf(getRequiredVersionProperty(vp, "isGAECompliant")); - - VERSION = new Version(versionString, gaeCompliant, buildDate); - } - } catch (IOException e) { - throw new RuntimeException("Failed to load and parse " + VERSION_PROPERTIES_PATH, e); - } - } - - private static final String FM_24_DETECTION_CLASS_NAME = "freemarker.core._2_4_OrLaterMarker"; - private static final boolean FM_24_DETECTED; - static { - boolean fm24detected; - try { - Class.forName(FM_24_DETECTION_CLASS_NAME); - fm24detected = true; - } catch (ClassNotFoundException e) { - fm24detected = false; - } catch (LinkageError e) { - fm24detected = true; - } catch (Throwable e) { - // Unexpected. We assume that there's no clash. - fm24detected = false; - } - FM_24_DETECTED = fm24detected; - } - - private final static Object defaultConfigLock = new Object(); - - private static volatile Configuration defaultConfig; - - private volatile boolean localizedLookup = true; - private boolean whitespaceStripping = true; - private int autoEscapingPolicy = ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY; - private OutputFormat outputFormat = UndefinedOutputFormat.INSTANCE; - private boolean outputFormatExplicitlySet; - private Boolean recognizeStandardFileExtensions; - private Map<String, ? extends OutputFormat> registeredCustomOutputFormats = Collections.emptyMap(); - private Version incompatibleImprovements; - private int tagSyntax = ANGLE_BRACKET_TAG_SYNTAX; - private int namingConvention = AUTO_DETECT_NAMING_CONVENTION; - private int tabSize = 8; // Default from JavaCC 3.x - - private TemplateCache cache; - - private boolean templateLoaderExplicitlySet; - private boolean templateLookupStrategyExplicitlySet; - private boolean templateNameFormatExplicitlySet; - private boolean cacheStorageExplicitlySet; - - private boolean objectWrapperExplicitlySet; - private boolean templateExceptionHandlerExplicitlySet; - private boolean logTemplateExceptionsExplicitlySet; - - private HashMap/*<String, TemplateModel>*/ sharedVariables = new HashMap(); - - /** - * Needed so that it doesn't mater in what order do you call {@link #setSharedVaribles(Map)} - * and {@link #setObjectWrapper(ObjectWrapper)}. When the user configures FreeMarker from Spring XML, he has no - * control over the order, so it has to work on both ways. - */ - private HashMap/*<String, Object>*/ rewrappableSharedVariables = null; - - private String defaultEncoding = SecurityUtilities.getSystemProperty("file.encoding", "utf-8"); - private ConcurrentMap localeToCharsetMap = new ConcurrentHashMap(); - - /** - * @deprecated Use {@link #Configuration(Version)} instead. Note that the version can be still modified later with - * {@link Configuration#setIncompatibleImprovements(Version)} (or - * {@link Configuration#setSettings(Properties)}). - */ - @Deprecated - public Configuration() { - this(DEFAULT_INCOMPATIBLE_IMPROVEMENTS); - } - - /** - * Creates a new instance and sets which of the non-backward-compatible bugfixes/improvements should be enabled. - * Note that the specified versions corresponds to the {@code incompatible_improvements} configuration setting, and - * can be changed later, with {@link #setIncompatibleImprovements(Version)} for example. - * - * <p><b>About the "incompatible improvements" setting</b> - * - * <p>This setting value is the FreeMarker version number where the not 100% backward compatible bug fixes and - * improvements that you want to enable were already implemented. In new projects you should set this to the - * FreeMarker version that you are actually using. In older projects it's also usually better to keep this high, - * however you better check the changes activated (find them below), at least if not only the 3rd version number - * (the micro version) of {@code incompatibleImprovements} is increased. Generally, as far as you only increase the - * last version number of this setting, the changes are always low risk. The default value is 2.3.0 to maximize - * backward compatibility, but that value isn't recommended. - * - * <p>Bugfixes and improvements that are fully backward compatible, also those that are important security fixes, - * are enabled regardless of the incompatible improvements setting. - * - * <p>An important consequence of setting this setting is that now your application will check if the stated minimum - * FreeMarker version requirement is met. Like if you set this setting to 2.3.22, but accidentally the application - * is deployed with FreeMarker 2.3.21, then FreeMarker will fail, telling that a higher version is required. After - * all, the fixes/improvements you have requested aren't available on a lower version. - * - * <p>Note that as FreeMarker's minor (2nd) or major (1st) version number increments, it's possible that emulating - * some of the old bugs will become unsupported, that is, even if you set this setting to a low value, it silently - * wont bring back the old behavior anymore. Information about that will be present here. - * - * <p>Currently the effects of this setting are: - * <ul> - * <li><p> - * 2.3.0: This is the lowest supported value, the version used in older projects. This is the default in the - * FreeMarker 2.3.x series. - * </li> - * <li><p> - * 2.3.19 (or higher): Bug fix: Wrong {@code #} tags were printed as static text instead of - * causing parsing error when there was no correct {@code #} or {@code @} tag earlier in the - * same template. - * </li> - * <li><p> - * 2.3.20 (or higher): {@code ?html} will escape apostrophe-quotes just like {@code ?xhtml} does. Utilizing - * this is highly recommended, because otherwise if interpolations are used inside attribute values that use - * apostrophe-quotation (<tt><foo bar='${val}'></tt>) instead of plain quotation mark - * (<tt><foo bar="${val}"></tt>), they might produce HTML/XML that's not well-formed. Note that - * {@code ?html} didn't do this because long ago there was no cross-browser way of doing this, but it's not a - * concern anymore. - * </li> - * <li><p> - * 2.3.21 (or higher): - * <ul> - * <li><p> - * The <em>default</em> of the {@code object_wrapper} setting ({@link #getObjectWrapper()}) changes from - * {@link ObjectWrapper#DEFAULT_WRAPPER} to another almost identical {@link DefaultObjectWrapper} singleton, - * returned by {@link DefaultObjectWrapperBuilder#build()}. The new default object wrapper's - * "incompatible improvements" version is set to the same as of the {@link Configuration}. - * See {@link BeansWrapper#BeansWrapper(Version)} for further details. Furthermore, the new default - * object wrapper doesn't allow changing its settings; setter methods throw {@link IllegalStateException}). - * (If anything tries to call setters on the old default in your application, that's a dangerous bug that - * won't remain hidden now. As the old default is a singleton too, potentially shared by independently - * developed components, most of them expects the out-of-the-box behavior from it (and the others are - * necessarily buggy). Also, then concurrency glitches can occur (and even pollute the class introspection - * cache) because the singleton is modified after publishing to other threads.) - * Furthermore the new default object wrapper shares class introspection cache with other - * {@link BeansWrapper}-s created with {@link BeansWrapperBuilder}, which has an impact as - * {@link BeansWrapper#clearClassIntrospecitonCache()} will be disallowed; see more about it there. - * </li> - * <li><p> - * The {@code ?iso_...} built-ins won't show the time zone offset for {@link java.sql.Time} values anymore, - * because most databases store time values that aren't in any time zone, but just store hour, minute, - * second, and decimal second field values. If you still want to show the offset (like for PostgreSQL - * "time with time zone" columns you should), you can force showing the time zone offset by using - * {@code myTime?string.iso_fz} (and its other variants). - * </li> - * <li><p>{@code ?is_enumerable} correctly returns {@code false} for Java methods get from Java objects that - * are wrapped with {@link BeansWrapper} and its subclasses, like {@link DefaultObjectWrapper}. Although - * method values implement {@link TemplateSequenceModel} (because of a historical design quirk in - * {@link BeansWrapper}), trying to {@code #list} them will cause error, hence they aren't enumerable. - * </li> - * <li><p> - * {@code ?c} will return {@code "INF"}, {@code "-INF"} and {@code "NaN"} for positive/negative infinity - * and IEEE floating point Not-a-Number, respectively. These are the XML Schema compatible representations - * of these special values. Earlier it has returned what {@link DecimalFormat} did with US locale, none of - * which was understood by any (common) computer language. - * </li> - * <li><p> - * FTL hash literals that repeat keys now only have the key once with {@code ?keys}, and only has the last - * value associated to that key with {@code ?values}. This is consistent with the behavior of - * {@code hash[key]} and how maps work in Java. - * </li> - * <li><p>In most cases (where FreeMarker is able to do that), for {@link TemplateLoader}-s that use - * {@link URLConnection}, {@code URLConnection#setUseCaches(boolean)} will called with {@code false}, - * so that only FreeMarker will do caching, not the URL scheme's handler. - * See {@link URLTemplateLoader#setURLConnectionUsesCaches(Boolean)} for more details. - * </li> - * <li><p> - * The default of the {@code template_loader} setting ({@link Configuration#getTemplateLoader()}) changes - * to {@code null}, which means that FreeMarker will not find any templates. Earlier - * the default was a {@link FileTemplateLoader} that used the current directory as the root. This was - * dangerous and fragile as you usually don't have good control over what the current directory will be. - * Luckily, the old default almost never looked for the templates at the right place - * anyway, so pretty much all applications had to set the {@code template_loader} setting, so it's unlikely - * that changing the default breaks your application. - * </li> - * <li><p> - * Right-unlimited ranges become readable (like listable), so {@code <#list 1.. as i>...</#list>} works. - * Earlier they were only usable for slicing (like {@code hits[10..]}). - * </li> - * <li><p> - * Empty ranges return {@link Constants#EMPTY_SEQUENCE} instead of an empty {@link SimpleSequence}. This - * is in theory backward compatible, as the API only promises to give something that implements - * {@link TemplateSequenceModel}. - * </li> - * <li><p> - * Unclosed comments ({@code <#-- ...}) and {@code #noparse}-s won't be silently closed at the end of - * template anymore, but cause a parsing error instead. - * </li> - * </ul> - * </li> - * <li><p> - * 2.3.22 (or higher): - * <ul> - * <li><p> - * {@link DefaultObjectWrapper} has some substantial changes with {@code incompatibleImprovements} 2.3.22; - * check them out at {@link DefaultObjectWrapper#DefaultObjectWrapper(Version)}. It's important to know - * that if you set the {@code object_wrapper} setting (to an other value than {@code "default"}), rather - * than leaving it on its default value, the {@code object_wrapper} won't inherit the - * {@code incompatibleImprovements} of the {@link Configuration}. In that case, if you want the 2.3.22 - * improvements of {@link DefaultObjectWrapper}, you have to set it in the {@link DefaultObjectWrapper} - * object itself too! (Note that it's OK to use a {@link DefaultObjectWrapper} with a different - * {@code incompatibleImprovements} version number than that of the {@link Configuration}, if that's - * really what you want.) - * </li> - * <li><p> - * In templates, {@code .template_name} will <em>always</em> return the main (top level) template's name. - * It won't be affected by {@code #include} and {@code #nested} anymore. This is unintended, a bug with - * {@code incompatible_improvement} 2.3.22 (a consequence of the lower level fixing described in the next - * point). The old behavior of {@code .template_name} is restored if you set - * {@code incompatible_improvement} to 2.3.23 (while {@link Configurable#getParent()}) of - * {@link Environment} keeps the changed behavior shown in the next point). - * </li> - * <li><p> - * {@code #include} and {@code #nested} doesn't change the parent {@link Template} (see - * {@link Configurable#getParent()}) of the {@link Environment} anymore to the {@link Template} that's - * included or whose namespace {@code #nested} "returns" to. Thus, the parent of {@link Environment} will - * be now always the main {@link Template}. (The main {@link Template} is the {@link Template} whose - * {@code process} or {@code createProcessingEnvironment} method was called to initiate the output - * generation.) Note that apart from the effect on FTL's {@code .template_name} (see - * previous point), this should only matter if you have set settings directly on {@link Template} objects, - * and almost nobody does that. Also note that macro calls have never changed the {@link Environment} - * parent to the {@link Template} that contains the macro definition, so this mechanism was always broken. - * As now we consistently never change the parent, the behavior when calling macros didn't change. - * </li> - * <li><p> - * When using {@code freemarker.ext.servlet.FreemarkerServlet}: - * <ul> - * <li> - * <p>When using custom JSP tag libraries: Fixes bug where some kind of - * values, when put into the JSP <em>page</em> scope (via {@code #global} or via the JSP - * {@code PageContext} API) and later read back with the JSP {@code PageContext} API (typically in a - * custom JSP tag), might come back as FreeMarker {@link TemplateModel} objects instead of as objects - * with a standard Java type. Other Servlet scopes aren't affected. It's highly unlikely that - * something expects the presence of this bug. The affected values are of the FTL types listed below, - * and to trigger the bug, they either had to be created directly in the template (like as an FTL - * literal or with {@code ?date}/{@code time}/{@code datetime}), or you had to use - * {@link DefaultObjectWrapper} or {@link SimpleObjectWrapper} (or a subclass of them): - * - * <ul> - * <li>FTL date/time/date-time values may came back as {@link SimpleDate}-s, now they come back as - * {@link java.util.Date java.util.Date}-s instead.</li> - * - * <li>FTL sequence values may came back as {@link SimpleSequence}-s, now they come back as - * {@link java.util.List}-s as expected. This at least stands assuming that the - * {@link Configuration#setSetting(String, String) object_wrapper} configuration setting is a - * subclass of {@link BeansWrapper} (such as {@link DefaultObjectWrapper}, which is the default), - * but that's practically always the case in applications that use FreeMarker's JSP extension - * (otherwise it can still work, but it depends on the quality and capabilities of the - * {@link ObjectWrapper} implementation).</li> - * - * <li>FTL hash values may came back as {@link SimpleHash}-es, now they come back as - * {@link java.util.Map}-s as expected (again, assuming that the object wrapper is a subclass of - * {@link BeansWrapper}, like preferably {@link DefaultObjectWrapper}, which is also the default). - * </li> - * - * <li>FTL collection values may came back as {@link SimpleCollection}-s, now they come back as - * {@link java.util.Collection}-s as expected (again, assuming that the object wrapper is a subclass - * of {@link BeansWrapper}, like preferably {@link DefaultObjectWrapper}).</li> - * </ul> - * </li> - * <li><p> - * Initial {@code "["} in the {@code TemplatePath} init-param - * has special meaning; it's used for specifying multiple comma separated locations, like in - * {@code <param-value>[ WEB-INF/templates, classpath:com/example/myapp/templates ]</param-value>} - * </li> - * <li><p> - * Initial <tt>"{"</tt> in the {@code TemplatePath} init-param is reserved for future purposes, and - * thus will throw exception. - * </li> - * </ul> - * </li> - * </ul> - * </li> - * <li><p> - * 2.3.23 (or higher): - * <ul> - * <li><p> - * Fixed a loophole in the implementation of the long existing parse-time rule that says that - * {@code #break}, in the FTL source code itself, must occur nested inside a breakable directive, such as - * {@code #list} or {@code #switch}. This check could be circumvented with {@code #macro} or - * {@code #function}, like this: - * {@code <#list 1..1 as x><#macro callMeLater><#break></#macro></#list><@callMeLater />}. - * After activating this fix, this will be a parse time error. - * </li> - * <li><p> - * If you have used {@code incompatible_improvements} 2.3.22 earlier, know that there the behavior of the - * {@code .template_name} special variable used in templates was accidentally altered, but now it's - * restored to be backward compatible with 2.3.0. (Ironically, the restored legacy behavior itself is - * broken when it comes to macro invocations, we just keep it for backward compatibility. If you need fixed - * behavior, use {@code .current_template_name} or {@code .main_template_name} instead.) - * </li> - * </ul> - * </li> - * <li><p> - * 2.3.24 (or higher): - * <ul> - * <li><p> - * The default of the - * {@link #setRecognizeStandardFileExtensions(boolean) recognize_standard_file_extensions} - * setting changes to {@code true}, which means that templates whose name ends with {@code ".ftlh"} or - * {@code ".ftlx"} will automatically get {@link HTMLOutputFormat#INSTANCE} or - * {@link XMLOutputFormat#INSTANCE} output format respectively, in both cases with - * {@link #ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY} {@link #setAutoEscapingPolicy(int) auto_escaping_policy}. - * These "file" extensions aren't case sensitive. - * </li> - * <li><p> - * In number format and date format strings (like in the {@code number_format} setting, or in templates in - * {@code n?string("0.##")}), an initial {@code '@'} has special meaning; they refer to a custom format - * with the name given after the {@code @} (see: {@link #setCustomNumberFormats(Map)}, - * {@link #setCustomDateFormats(Map)}, {@link #setNumberFormat(String)}, and {@link #setDateTimeFormat}). - * If the custom format doesn't exist, that will be an error. To have a literal {@code @} as the first - * character in the output, it has to be written as {@code @@}. Again, all this only applies to the very - * first character of the format string, so {@code @} characters elsewhere must not be doubled. Also, if - * there are any custom formats defined, initial {@code '@'} will have the new meaning regardless of - * the value of the {@code incompatible_improvements} setting. So you don't need to set the - * {@code incompatible_improvements} only to use custom formats. - * </li> - * <li><p> - * Expressions inside interpolations that were inside <em>string literal expressions</em> - * (not <code>${...}</code>-s in general), like in <code><#assign s="Hello ${name}!"></code>, has - * always used {@code incompatbileImprovement}-s 0 (2.3.0 in effect). Now it's fixed. - * </li> - * <li><p> - * {@link DefaultObjectWrapper} has some minor changes with {@code incompatibleImprovements} 2.3.24; - * check them out at {@link DefaultObjectWrapper#DefaultObjectWrapper(Version)}. It's important to know - * that if you set the {@code object_wrapper} setting (to an other value than {@code "default"}), rather - * than leaving it on its default value, the {@code object_wrapper} won't inherit the - * {@code incompatibleImprovements} of the {@link Configuration}. In that case, if you want the 2.3.24 - * improvements of {@link DefaultObjectWrapper}, you have to set it in the {@link DefaultObjectWrapper} - * object itself too! (Note that it's OK to use a {@link DefaultObjectWrapper} with a different - * {@code incompatibleImprovements} version number than that of the {@link Configuration}, if that's - * really what you want.) - * </li> - * <li><p> - * Fixed bug: The {@code #import} directive meant to copy the library variable into a global variable if - * it's executed in the main namespace, but that haven't happened when the imported template was already - * imported earlier in another namespace. - * </li> - * <li><p> - * {@code ?is_sequence} doesn't return {@code true} for Java methods wrapped by {@link BeansWrapper} and - * its subclasses (most notably {@link DefaultObjectWrapper}) anymore, as they only implement the - * {@code [index]} operator, but not {@code ?size}, which causes {@code <#list ...>} to fail among others. - * (They shouldn't implement either, but this is historical heritage.) - * </ul> - * </li> - * <li><p> - * 2.3.25 (or higher): - * <ul> - * <li><p> - * When calling {@link Configurable#setAutoIncludes(List)} on a {@link Configuration}, it filters out - * duplicates from the list, similarly as repeatedly calling {@link Configurable#addAutoInclude(String)} - * would, hence avoiding repeated inclusions. Calling {@link Configurable#setAutoIncludes(List)} on other - * {@link Configurable}-s always do this filtering regardless of the incompatible improvements setting. - * </ul> - * </li> - * </ul> - * - * @throws IllegalArgumentException - * If {@code incompatibleImmprovements} refers to a version that wasn't released yet when the currently - * used FreeMarker version was released, or is less than 2.3.0, or is {@code null}. - * - * @since 2.3.21 - */ - public Configuration(Version incompatibleImprovements) { - super(incompatibleImprovements); - - // We postpone this until here (rather that doing this in static initializer) for two reason: - // - Class initialization errors are often not reported very well - // - This way we avoid the error if FM isn't actually used - checkFreeMarkerVersionClash(); - - NullArgumentException.check("incompatibleImprovements", incompatibleImprovements); - this.incompatibleImprovements = incompatibleImprovements; - - createTemplateCache(); - loadBuiltInSharedVariables(); - } - - private static void checkFreeMarkerVersionClash() { - if (FM_24_DETECTED) { - throw new RuntimeException("Clashing FreeMarker versions (" + VERSION + " and some post-2.3.x) detected: " - + "found post-2.3.x class " + FM_24_DETECTION_CLASS_NAME + ". You probably have two different " - + "freemarker.jar-s in the classpath."); - } - } - - private void createTemplateCache() { - cache = new TemplateCache( - null, - getDefaultCacheStorage(), - getDefaultTemplateLookupStrategy(), - getDefaultTemplateNameFormat(), - null, - this); - cache.clear(); // for fully BC behavior - cache.setDelay(5000); - } - - private void recreateTemplateCacheWith( - TemplateLoader loader, CacheStorage storage, - TemplateLookupStrategy templateLookupStrategy, TemplateNameFormat templateNameFormat, - TemplateConfigurationFactory templateConfigurations) { - TemplateCache oldCache = cache; - cache = new TemplateCache( - loader, storage, templateLookupStrategy, templateNameFormat, templateConfigurations, this); - cache.clear(false); - cache.setDelay(oldCache.getDelay()); - cache.setLocalizedLookup(localizedLookup); - } - - private void recreateTemplateCache() { - recreateTemplateCacheWith(cache.getTemplateLoader(), cache.getCacheStorage(), - cache.getTemplateLookupStrategy(), cache.getTemplateNameFormat(), - getTemplateConfigurations()); - } - - private TemplateLookupStrategy getDefaultTemplateLookupStrategy() { - return getDefaultTemplateLookupStrategy(getIncompatibleImprovements()); - } - - static TemplateLookupStrategy getDefaultTemplateLookupStrategy(Version incompatibleImprovements) { - return TemplateLookupStrategy.DEFAULT_2_3_0; - } - - private TemplateNameFormat getDefaultTemplateNameFormat() { - return getDefaultTemplateNameFormat(getIncompatibleImprovements()); - } - - static TemplateNameFormat getDefaultTemplateNameFormat(Version incompatibleImprovements) { - return TemplateNameFormat.DEFAULT_2_3_0; - } - - private CacheStorage getDefaultCacheStorage() { - return createDefaultCacheStorage(getIncompatibleImprovements(), getCacheStorage()); - } - - static CacheStorage createDefaultCacheStorage(Version incompatibleImprovements, CacheStorage existingCacheStorage) { - if (existingCacheStorage instanceof DefaultSoftCacheStorage) { - return existingCacheStorage; - } - return new DefaultSoftCacheStorage(); - } - - static CacheStorage createDefaultCacheStorage(Version incompatibleImprovements) { - return createDefaultCacheStorage(incompatibleImprovements, null); - } - - private static class DefaultSoftCacheStorage extends SoftCacheStorage { - // Nothing to override - } - - private TemplateExceptionHandler getDefaultTemplateExceptionHandler() { - return getDefaultTemplateExceptionHandler(getIncompatibleImprovements()); - } - - private boolean getDefaultLogTemplateExceptions() { - return getDefaultLogTemplateExceptions(getIncompatibleImprovements()); - } - - private ObjectWrapper getDefaultObjectWrapper() { - return getDefaultObjectWrapper(getIncompatibleImprovements()); - } - - // Package visible as Configurable needs this to initialize the field defaults. - final static TemplateExceptionHandler getDefaultTemplateExceptionHandler(Version incompatibleImprovements) { - return TemplateExceptionHandler.DEBUG_HANDLER; - } - - // Package visible as Configurable needs this to initialize the field defaults. - final static boolean getDefaultLogTemplateExceptions(Version incompatibleImprovements) { - return true; - } - - @Override - public Object clone() { - try { - Configuration copy = (Configuration) super.clone(); - copy.sharedVariables = new HashMap(sharedVariables); - copy.localeToCharsetMap = new ConcurrentHashMap(localeToCharsetMap); - copy.recreateTemplateCacheWith( - cache.getTemplateLoader(), cache.getCacheStorage(), - cache.getTemplateLookupStrategy(), cache.getTemplateNameFormat(), - cache.getTemplateConfigurations()); - return copy; - } catch (CloneNotSupportedException e) { - throw new BugException("Cloning failed", e); - } - } - - private void loadBuiltInSharedVariables() { - sharedVariables.put("capture_output", new CaptureOutput()); - sharedVariables.put("compress", StandardCompress.INSTANCE); - sharedVariables.put("html_escape", new HtmlEscape()); - sharedVariables.put("normalize_newlines", new NormalizeNewlines()); - sharedVariables.put("xml_escape", new XmlEscape()); - } - - /** - * Loads a preset language-to-encoding map, similarly as if you have called - * {@link #clearEncodingMap()} and then did multiple {@link #setEncoding(Locale, String)} calls. - * 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: - * - * <table style="width: auto; border-collapse: collapse" border="1" summary="preset language to encoding mapping"> - * <tr><td>ar</td><td>ISO-8859-6</td></tr> - * <tr><td>be</td><td>ISO-8859-5</td></tr> - * <tr><td>bg</td><td>ISO-8859-5</td></tr> - * <tr><td>ca</td><td>ISO-8859-1</td></tr> - * <tr><td>cs</td><td>ISO-8859-2</td></tr> - * <tr><td>da</td><td>ISO-8859-1</td></tr> - * <tr><td>de</td><td>ISO-8859-1</td></tr> - * <tr><td>el</td><td>ISO-8859-7</td></tr> - * <tr><td>en</td><td>ISO-8859-1</td></tr> - * <tr><td>es</td><td>ISO-8859-1</td></tr> - * <tr><td>et</td><td>ISO-8859-1</td></tr> - * <tr><td>fi</td><td>ISO-8859-1</td></tr> - * <tr><td>fr</td><td>ISO-8859-1</td></tr> - * <tr><td>hr</td><td>ISO-8859-2</td></tr> - * <tr><td>hu</td><td>ISO-8859-2</td></tr> - * <tr><td>is</td><td>ISO-8859-1</td></tr> - * <tr><td>it</td><td>ISO-8859-1</td></tr> - * <tr><td>iw</td><td>ISO-8859-8</td></tr> - * <tr><td>ja</td><td>Shift_JIS</td></tr> - * <tr><td>ko</td><td>EUC-KR</td></tr> - * <tr><td>lt</td><td>ISO-8859-2</td></tr> - * <tr><td>lv</td><td>ISO-8859-2</td></tr> - * <tr><td>mk</td><td>ISO-8859-5</td></tr> - * <tr><td>nl</td><td>ISO-8859-1</td></tr> - * <tr><td>no</td><td>ISO-8859-1</td></tr> - * <tr><td>pl</td><td>ISO-8859-2</td></tr> - * <tr><td>pt</td><td>ISO-8859-1</td></tr> - * <tr><td>ro</td><td>ISO-8859-2</td></tr> - * <tr><td>ru</td><td>ISO-8859-5</td></tr> - * <tr><td>sh</td><td>ISO-8859-5</td></tr> - * <tr><td>sk</td><td>ISO-8859-2</td></tr> - * <tr><td>sl</td><td>ISO-8859-2</td></tr> - * <tr><td>sq</td><td>ISO-8859-2</td></tr> - * <tr><td>sr</td><td>ISO-8859-5</td></tr> - * <tr><td>sv</td><td>ISO-8859-1</td></tr> - * <tr><td>tr</td><td>ISO-8859-9</td></tr> - * <tr><td>uk</td><td>ISO-8859-5</td></tr> - * <tr><td>zh</td><td>GB2312</td></tr> - * <tr><td>zh_TW</td><td>Big5</td></tr> - * </table> - * - * @see #clearEncodingMap() - * @see #setEncoding(Locale, String) - * @see #setDefaultEncoding(String) - */ - public void loadBuiltInEncodingMap() { - localeToCharsetMap.clear(); - localeToCharsetMap.put("ar", "ISO-8859-6"); - localeToCharsetMap.put("be", "ISO-8859-5"); - localeToCharsetMap.put("bg", "ISO-8859-5"); - localeToCharsetMap.put("ca", "ISO-8859-1"); - localeToCharsetMap.put("cs", "ISO-8859-2"); - localeToCharsetMap.put("da", "ISO-8859-1"); - localeToCharsetMap.put("de", "ISO-8859-1"); - localeToCharsetMap.put("el", "ISO-8859-7"); - localeToCharsetMap.put("en", "ISO-8859-1"); - localeToCharsetMap.put("es", "ISO-8859-1"); - localeToCharsetMap.put("et", "ISO-8859-1"); - localeToCharsetMap.put("fi", "ISO-8859-1"); - localeToCharsetMap.put("fr", "ISO-8859-1"); - localeToCharsetMap.put("hr", "ISO-8859-2"); - localeToCharsetMap.put("hu", "ISO-8859-2"); - localeToCharsetMap.put("is", "ISO-8859-1"); - localeToCharsetMap.put("it", "ISO-8859-1"); - localeToCharsetMap.put("iw", "ISO-8859-8"); - localeToCharsetMap.put("ja", "Shift_JIS"); - localeToCharsetMap.put("ko", "EUC-KR"); - localeToCharsetMap.put("lt", "ISO-8859-2"); - localeToCharsetMap.put("lv", "ISO-8859-2"); - localeToCharsetMap.put("mk", "ISO-8859-5"); - localeToCharsetMap.put("nl", "ISO-8859-1"); - localeToCharsetMap.put("no", "ISO-8859-1"); - localeToCharsetMap.put("pl", "ISO-8859-2"); - localeToCharsetMap.put("pt", "ISO-8859-1"); - localeToCharsetMap.put("ro", "ISO-8859-2"); - localeToCharsetMap.put("ru", "ISO-8859-5"); - localeToCharsetMap.put("sh", "ISO-8859-5"); - localeToCharsetMap.put("sk", "ISO-8859-2"); - localeToCharsetMap.put("sl", "ISO-8859-2"); - localeToCharsetMap.put("sq", "ISO-8859-2"); - localeToCharsetMap.put("sr", "ISO-8859-5"); - localeToCharsetMap.put("sv", "ISO-8859-1"); - localeToCharsetMap.put("tr", "ISO-8859-9"); - localeToCharsetMap.put("uk", "ISO-8859-5"); - localeToCharsetMap.put("zh", "GB2312"); - localeToCharsetMap.put("zh_TW", "Big5"); - } - - /** - * Clears language-to-encoding map. - * @see #loadBuiltInEncodingMap - * @see #setEncoding - */ - public void clearEncodingMap() { - localeToCharsetMap.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 <code>new Configuration()</code> when the component - * is initialized. - */ - @Deprecated - static public Configuration getDefaultConfiguration() { - Configuration defaultConfig = Configuration.defaultConfig; - if (defaultConfig == null) { - synchronized (defaultConfigLock) { - defaultConfig = Configuration.defaultConfig; - if (defaultConfig == null) { - defaultConfig = new Configuration(); - Configuration.defaultConfig = defaultConfig; - } - } - } - 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...}. - */ - @Deprecated - static public void setDefaultConfiguration(Configuration config) { - synchronized (defaultConfigLock) { - defaultConfig = config; - } - } - - /** - * Sets a {@link TemplateLoader} that is used to look up and load templates; - * as a side effect the template cache will be emptied. - * By providing your own {@link TemplateLoader} implementation, you can load templates from whatever kind of - * storages, like from relational databases, NoSQL-storages, etc. - * - * <p>Convenience methods exists to install commonly used loaders, instead of using this method: - * {@link #setClassForTemplateLoading(Class, String)}, - * {@link #setClassLoaderForTemplateLoading(ClassLoader, String)}, - * {@link #setDirectoryForTemplateLoading(File)}, and - * {@link #setServletContextForTemplateLoading(Object, String)}. - * - * <p>You can chain several {@link TemplateLoader}-s together with {@link MultiTemplateLoader}. - * - * <p>Default value: You should always set the template loader instead of relying on the default value. - * (But if you still care what it is, before "incompatible improvements" 2.3.21 it's a {@link FileTemplateLoader} - * that uses the current directory as its root; as it's hard tell what that directory will be, it's not very useful - * and dangerous. Starting with "incompatible improvements" 2.3.21 the default is {@code null}.) - */ - public void setTemplateLoader(TemplateLoader templateLoader) { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (cache.getTemplateLoader() != templateLoader) { - recreateTemplateCacheWith(templateLoader, cache.getCacheStorage(), - cache.getTemplateLookupStrategy(), cache.getTemplateNameFormat(), - cache.getTemplateConfigurations()); - } - templateLoaderExplicitlySet = true; - } - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isTemplateLoaderExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetTemplateLoader() { - if (templateLoaderExplicitlySet) { - setTemplateLoader(null); - templateLoaderExplicitlySet = false; - } - } - - /** - * Tells if {@link #setTemplateLoader(TemplateLoader)} (or equivalent) was already called on this instance. - * - * @since 2.3.22 - */ - public boolean isTemplateLoaderExplicitlySet() { - return templateLoaderExplicitlySet; - } - - /** - * The getter pair of {@link #setTemplateLoader(TemplateLoader)}. - */ - public TemplateLoader getTemplateLoader() { - if (cache == null) { - return null; - } - return cache.getTemplateLoader(); - } - - /** - * Sets a {@link TemplateLookupStrategy} that is used to look up templates based on the requested name; as a side - * effect the template cache will be emptied. The default value is {@link TemplateLookupStrategy#DEFAULT_2_3_0}. - * - * @since 2.3.22 - */ - public void setTemplateLookupStrategy(TemplateLookupStrategy templateLookupStrategy) { - if (cache.getTemplateLookupStrategy() != templateLookupStrategy) { - recreateTemplateCacheWith(cache.getTemplateLoader(), cache.getCacheStorage(), - templateLookupStrategy, cache.getTemplateNameFormat(), - cache.getTemplateConfigurations()); - } - templateLookupStrategyExplicitlySet = true; - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isTemplateLookupStrategyExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetTemplateLookupStrategy() { - if (templateLookupStrategyExplicitlySet) { - setTemplateLookupStrategy(getDefaultTemplateLookupStrategy()); - templateLookupStrategyExplicitlySet = false; - } - } - - /** - * Tells if {@link #setTemplateLookupStrategy(TemplateLookupStrategy)} (or equivalent) was already called on this - * instance. - * - * @since 2.3.22 - */ - public boolean isTemplateLookupStrategyExplicitlySet() { - return templateLookupStrategyExplicitlySet; - } - - /** - * The getter pair of {@link #setTemplateLookupStrategy(TemplateLookupStrategy)}. - */ - public TemplateLookupStrategy getTemplateLookupStrategy() { - if (cache == null) { - return null; - } - return cache.getTemplateLookupStrategy(); - } - - /** - * Sets the template name format used. The default is {@link TemplateNameFormat#DEFAULT_2_3_0}, while the - * recommended value for new projects is {@link TemplateNameFormat#DEFAULT_2_4_0}. - * - * @since 2.3.22 - */ - public void setTemplateNameFormat(TemplateNameFormat templateNameFormat) { - if (cache.getTemplateNameFormat() != templateNameFormat) { - recreateTemplateCacheWith(cache.getTemplateLoader(), cache.getCacheStorage(), - cache.getTemplateLookupStrategy(), templateNameFormat, - cache.getTemplateConfigurations()); - } - templateNameFormatExplicitlySet = true; - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isTemplateNameFormatExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetTemplateNameFormat() { - if (templateNameFormatExplicitlySet) { - setTemplateNameFormat(getDefaultTemplateNameFormat()); - templateNameFormatExplicitlySet = false; - } - } - - /** - * Tells if {@link #setTemplateNameFormat(TemplateNameFormat)} (or equivalent) was already called on this instance. - * - * @since 2.3.22 - */ - public boolean isTemplateNameFormatExplicitlySet() { - return templateNameFormatExplicitlySet; - } - - /** - * The getter pair of {@link #setTemplateNameFormat(TemplateNameFormat)}. - */ - public TemplateNameFormat getTemplateNameFormat() { - if (cache == null) { - return null; - } - return cache.getTemplateNameFormat(); - } - - /** - * Sets a {@link TemplateConfigurationFactory} that will configure individual templates where their settings differ - * from those coming from the common {@link Configuration} object. A typical use case for that is specifying the - * {@link TemplateConfiguration#setOutputFormat(OutputFormat) outputFormat} for templates based on their file - * extension or parent directory. - * - * <p> - * Note that the settings suggested by standard file extensions are stronger than that you set here. See - * {@link #setRecognizeStandardFileExtensions(boolean)} for more information about standard file extensions. - * - * <p>See "Template configurations" in the FreeMarker Manual for examples. - * - * @since 2.3.24 - */ - public void setTemplateConfigurations(TemplateConfigurationFactory templateConfigurations) { - if (cache.getTemplateConfigurations() != templateConfigurations) { - if (templateConfigurations != null) { - templateConfigurations.setConfiguration(this); - } - recreateTemplateCacheWith(cache.getTemplateLoader(), cache.getCacheStorage(), - cache.getTemplateLookupStrategy(), cache.getTemplateNameFormat(), - templateConfigurations); - } - } - - /** - * The getter pair of {@link #setTemplateConfigurations(TemplateConfigurationFactory)}. - */ - public TemplateConfigurationFactory getTemplateConfigurations() { - if (cache == null) { - return null; - } - return cache.getTemplateConfigurations(); - } - - /** - * Sets the {@link CacheStorage} used for caching {@link Template}-s; - * the earlier content of the template cache will be dropt. - * - * 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 {@code null}). - * - * <p>Note that setting the cache storage will re-create the template cache, so - * all its content will be lost. - */ - public void setCacheStorage(CacheStorage cacheStorage) { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (getCacheStorage() != cacheStorage) { - recreateTemplateCacheWith(cache.getTemplateLoader(), cacheStorage, - cache.getTemplateLookupStrategy(), cache.getTemplateNameFormat(), - cache.getTemplateConfigurations()); - } - cacheStorageExplicitlySet = true; - } - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isCacheStorageExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetCacheStorage() { - if (cacheStorageExplicitlySet) { - setCacheStorage(getDefaultCacheStorage()); - cacheStorageExplicitlySet = false; - } - } - - /** - * Tells if {@link #setCacheStorage(CacheStorage)} (or equivalent) was already called on this instance. - * - * @since 2.3.22 - */ - public boolean isCacheStorageExplicitlySet() { - return cacheStorageExplicitlySet; - } - - /** - * The getter pair of {@link #setCacheStorage(CacheStorage)}. - * - * @since 2.3.20 - */ - public CacheStorage getCacheStorage() { - // "synchronized" is removed from the API as it's not safe to set anything after publishing the Configuration - synchronized (this) { - if (cache == null) { - return null; - } - return cache.getCacheStorage(); - } - } - - /** - * Sets the file system directory from which to load templates. This is equivalent to - * {@code setTemplateLoader(new FileTemplateLoader(dir))}, so see - * {@link FileTemplateLoader#FileTemplateLoader(File)} for more details. - * - * <p> - * Note that FreeMarker can load templates from non-file-system sources too. See - * {@link #setTemplateLoader(TemplateLoader)} from more details. - * - * <p> - * Note that this shouldn't be used for loading templates that are coming from a WAR; use - * {@link #setServletContextForTemplateLoading(Object, String)} then. Servlet containers might not unpack the WAR - * file, in which case you clearly can't access the contained files via {@link File}. Even if the WAR is unpacked, - * the servlet container might not expose the location as a {@link File}. - * {@link #setServletContextForTemplateLoading(Object, String)} on the other hand will work in all these cases. - */ - 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. - * This is equivalent to {@code setTemplateLoader(new WebAppTemplateLoader(sctxt, path))} - * or {@code setTemplateLoader(new WebAppTemplateLoader(sctxt))} if {@code path} was - * {@code null}, so see {@code freemarker.cache.WebAppTemplateLoader} for more details. - * - * @param servletContext the {@code javax.servlet.ServletContext} object. (The declared type is {@link Object} - * to prevent class loading error when using FreeMarker in an environment where - * there's no servlet classes available.) - * @param path the path relative to the ServletContext. - * - * @see #setTemplateLoader(TemplateLoader) - */ - public void setServletContextForTemplateLoading(Object servletContext, String path) { - try { - // Don't introduce linking-time dependency on servlets - final Class webappTemplateLoaderClass = ClassUtil.forName("freemarker.cache.WebAppTemplateLoader"); - - // Don't introduce linking-time dependency on servlets - final Class servletContextClass = ClassUtil.forName("javax.servlet.ServletContext"); - - final Class[] constructorParamTypes; - final Object[] constructorParams; - if (path == null) { - constructorParamTypes = new Class[] { servletContextClass }; - constructorParams = new Object[] { servletContext }; - } else { - constructorParamTypes = new Class[] { servletContextClass, String.class }; - constructorParams = new Object[] { servletContext, path }; - } - - setTemplateLoader( (TemplateLoader) - webappTemplateLoaderClass - .getConstructor(constructorParamTypes) - .newInstance(constructorParams)); - } catch (Exception e) { - throw new BugException(e); - } - } - - /** - * Sets the class whose {@link Class#getResource(String)} method will be used to load templates, from the inside the - * package specified. See {@link ClassTemplateLoader#ClassTemplateLoader(Class, String)} for more details. - * - * @param basePackagePath - * Separate steps with {@code "/"}, not {@code "."}, and note that it matters if this starts with - * {@code /} or not. See {@link ClassTemplateLoader#ClassTemplateLoader(Class, String)} for more details. - * - * @see #setClassLoaderForTemplateLoading(ClassLoader, String) - * @see #setTemplateLoader(TemplateLoader) - */ - public void setClassForTemplateLoading(Class resourceLoaderClass, String basePackagePath) { - setTemplateLoader(new ClassTemplateLoader(resourceLoaderClass, basePackagePath)); - } - - /** - * Sets the {@link ClassLoader} whose {@link ClassLoader#getResource(String)} method will be used to load templates, - * from the inside the package specified. See {@link ClassTemplateLoader#ClassTemplateLoader(Class, String)} for - * more details. - * - * @param basePackagePath - * Separate steps with {@code "/"}, not {@code "."}. See - * {@link ClassTemplateLoader#ClassTemplateLoader(Class, String)} for more details. - * - * @see #setClassForTemplateLoading(Class, String) - * @see #setTemplateLoader(TemplateLoader) - * - * @since 2.3.22 - */ - public void setClassLoaderForTemplateLoading(ClassLoader classLoader, String basePackagePath) { - setTemplateLoader(new ClassTemplateLoader(classLoader, basePackagePath)); - } - - /** - * Sets the time in seconds that must elapse before checking whether there is a newer version of a template "file" - * than the cached one. - * - * <p> - * Historical note: Despite what the API documentation said earlier, this method is <em>not</em> thread-safe. While - * it works well on most hardware, it's not guaranteed that FreeMarker will see the update in all threads, and - * theoretically it's also possible that it will see a value that's a binary mixture of the new and the old one. - * - * @deprecated Use {@link #setTemplateUpdateDelayMilliseconds(long)} instead, because the time granularity of this method - * is often misunderstood to be milliseconds. - */ - @Deprecated - public void setTemplateUpdateDelay(int seconds) { - cache.setDelay(1000L * seconds); - } - - /** - * Sets the time in milliseconds that must elapse before checking whether there is a newer version of a template - * "file" exists than the cached one. Defaults to 5000 ms. - * - * <p> - * When you get a template via {@link #getTemplate(String)} (or some of its overloads). FreeMarker will try to get - * the template from the template cache. If the template is found, and at least this amount of time was elapsed - * since the template last modification date was checked, FreeMarker will re-check the last modification date (this - * could mean I/O), possibly reloading the template and updating the cache as a consequence (can mean even more - * I/O). The {@link #getTemplate(String)} (or some of its overloads) call will only return after this all is - * done, so it will return the fresh template. - * - * @since 2.3.23 - */ - public void setTemplateUpdateDelayMilliseconds(long millis) { - cache.setDelay(millis); - } - - /** - * The getter pair of {@link #setTemplateUpdateDelayMilliseconds(long)}. - * - * @since 2.3.23 - */ - public long getTemplateUpdateDelayMilliseconds() { - return cache.getDelay(); - } - - @Override - public void setObjectWrapper(ObjectWrapper objectWrapper) { - ObjectWrapper prevObjectWrapper = getObjectWrapper(); - super.setObjectWrapper(objectWrapper); - objectWrapperExplicitlySet = true; - if (objectWrapper != prevObjectWrapper) { - try { - setSharedVariablesFromRewrappableSharedVariables(); - } catch (TemplateModelException e) { - throw new RuntimeException( - "Failed to re-wrap earliearly set shared variables with the newly set object wrapper", - e); - } - } - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isObjectWrapperExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetObjectWrapper() { - if (objectWrapperExplicitlySet) { - setObjectWrapper(getDefaultObjectWrapper()); - objectWrapperExplicitlySet = false; - } - } - - /** - * Tells if {@link #setObjectWrapper(ObjectWrapper)} (or equivalent) was already called on this instance. - * - * @since 2.3.22 - */ - public boolean isObjectWrapperExplicitlySet() { - return objectWrapperExplicitlySet; - } - - @Override - public void setTemplateExceptionHandler(TemplateExceptionHandler templateExceptionHandler) { - super.setTemplateExceptionHandler(templateExceptionHandler); - templateExceptionHandlerExplicitlySet = true; - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isTemplateExceptionHandlerExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetTemplateExceptionHandler() { - if (templateExceptionHandlerExplicitlySet) { - setTemplateExceptionHandler(getDefaultTemplateExceptionHandler()); - templateExceptionHandlerExplicitlySet = false; - } - } - - /** - * Tells if {@link #setTemplateExceptionHandler(TemplateExceptionHandler)} (or equivalent) was already called on - * this instance. - * - * @since 2.3.22 - */ - public boolean isTemplateExceptionHandlerExplicitlySet() { - return templateExceptionHandlerExplicitlySet; - } - - /** - * @since 2.3.22 - */ - @Override - public void setLogTemplateExceptions(boolean value) { - super.setLogTemplateExceptions(value); - logTemplateExceptionsExplicitlySet = true; - } - - /** - * Resets the setting to its default, as if it was never set. This means that when you change the - * {@code incompatibe_improvements} setting later, the default will also change as appropriate. Also - * {@link #isTemplateExceptionHandlerExplicitlySet()} will return {@code false}. - * - * @since 2.3.22 - */ - public void unsetLogTemplateExceptions() { - if (logTemplateExceptionsExplicitlySet) { - setLogTemplateExceptions(getDefaultLogTemplateExceptions()); - logTemplateExceptionsExplicitlySet = false; - } - } - - /** - * Tells if {@link #setLogTemplateExceptions(boolean)} (or equivalent) was already called on this instance. - * - * @since 2.3.22 - */ - public boolean isLogTemplateExceptionsExplicitlySet() { - return logTemplateExceptionsExplicitlySet; - } - - /** - * Use {@link #Configuration(Version)} instead if possible; see the meaning of the parameter there. - * If the default value of a setting depends on the {@code incompatibleImprovements} and the value of that setting - * was never set in this {@link Configuration} object through the public API, its value will be set to the default - * value appropriate for the new {@code incompatibleImprovements}. (This adjustment of a setting value doesn't - * count as setting that setting, so setting {@code incompatibleImprovements} for multiple times also works as - * expected.) Note that if the {@code template_loader} have to be changed because of this, the template cache will - * be emptied. - * - * @throws IllegalArgumentException - * If {@code incompatibleImmprovements} refers to a version that wasn't released yet when the currently - * used FreeMarker version was released, or is less than 2.3.0, or is {@code null}. - * - * @since 2.3.20 - */ - public void setIncompatibleImprovements(Version incompatibleImprovements) { - _TemplateAPI.checkVersionNotNullAndSupported(incompatibleImprovements); - - if (!this.incompatibleImprovements.equals(incompatibleImprovements)) { - this.incompatibleImprovements = incompatibleImprovements; - - if (!templateLoaderExplicitlySet) { - templateLoaderExplicitlySet = true; - unsetTemplateLoader(); - } - - if (!templateLookupStrategyExplicitlySet) { - templateLookupStrategyExplicitlySet = true; - unsetTemplateLookupStrategy(); - } - - if (!templateNameFormatExplicitlySet) { - templateNameFormatExplicitlySet = true; - unsetTemplateNameFormat(); - } - - if (!cacheStorageExplicitlySet) { - cacheStorageExplicitlySet = true; - unsetCacheStorage(); - } - - if (!templateE
<TRUNCATED>
