| /* |
| * 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.IOException; |
| import java.io.PrintStream; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import freemarker.cache.TemplateCache; |
| import freemarker.cache.TemplateLoader; |
| import freemarker.cache.TemplateLookupStrategy; |
| import freemarker.core.Configurable; |
| import freemarker.core.Environment; |
| import freemarker.core.LibraryLoad; |
| import freemarker.core.Macro; |
| import freemarker.core.OutputFormat; |
| import freemarker.core.ParseException; |
| import freemarker.core.ParserConfiguration; |
| import freemarker.core.TemplateConfiguration; |
| import freemarker.core.TemplateElement; |
| import freemarker.core.UnboundTemplate; |
| import freemarker.core._CoreAPI; |
| import freemarker.debug.impl.DebuggerService; |
| |
| /** |
| * <p>Stores an already parsed template, ready to be processed (rendered) for unlimited times, possibly from |
| * multiple threads. |
| * |
| * <p>Typically, you will use {@link Configuration#getTemplate(String)} to create/get {@link Template} objects, so |
| * you don't construct them directly. But you can also construct a template from a {@link Reader} or a {@link String} |
| * that contains the template source code. But then it's |
| * important to know that while the resulting {@link Template} is efficient for later processing, creating a new |
| * {@link Template} itself is relatively expensive. So try to re-use {@link Template} objects if possible. |
| * {@link Configuration#getTemplate(String)} does that (caching {@link Template}-s) for you, but the constructor of |
| * course doesn't, so it's up to you to solve then. |
| * |
| * <p>Objects of this class meant to be handled as immutable and thus thread-safe. However, it has some setter methods |
| * for changing FreeMarker settings. Those must not be used while the template is being processed, or if the |
| * template object is already accessible from multiple threads. |
| */ |
| public class Template extends Configurable { |
| public static final String DEFAULT_NAMESPACE_PREFIX = UnboundTemplate.DEFAULT_NAMESPACE_PREFIX; |
| public static final String NO_NS_PREFIX = UnboundTemplate.NO_NS_PREFIX; |
| |
| private final UnboundTemplate unboundTemplate; |
| private final String name; |
| private String encoding; |
| private Object customLookupCondition; |
| |
| /** |
| * A prime constructor to which all other constructors should |
| * delegate directly or indirectly. |
| */ |
| private Template(UnboundTemplate unboundTemplate, String name, Configuration cfg) { |
| super(toNonNull(cfg)); |
| this.unboundTemplate = unboundTemplate; |
| this.name = name; |
| } |
| |
| /** |
| * To be used internally only! |
| */ |
| Template(UnboundTemplate unboundTemplate, |
| String name, Locale locale, Object customLookupCondition, |
| Configuration cfg) { |
| this(unboundTemplate, name, cfg); |
| this.setLocale(locale); |
| this.setCustomLookupCondition(customLookupCondition); |
| } |
| |
| private static Configuration toNonNull(Configuration cfg) { |
| return cfg != null ? cfg : Configuration.getDefaultConfiguration(); |
| } |
| |
| /** |
| * Same as {@link #Template(String, String, Reader, Configuration)} with {@code null} {@code sourceName} parameter. |
| */ |
| public Template(String name, Reader reader, Configuration cfg) throws IOException { |
| this(name, null, reader, cfg); |
| } |
| |
| /** |
| * Convenience constructor for {@link #Template(String, Reader, Configuration) |
| * Template(name, new StringReader(reader), cfg)}. |
| * |
| * @since 2.3.20 |
| */ |
| public Template(String name, String sourceCode, Configuration cfg) throws IOException { |
| this(name, new StringReader(sourceCode), cfg); |
| } |
| |
| /** |
| * Convenience constructor for {@link #Template(String, String, Reader, Configuration, String) Template(name, null, |
| * reader, cfg, encoding)}. |
| * |
| * @deprecated In most applications, use {@link #Template(String, Reader, Configuration)} instead, which doesn't |
| * specify the encoding. |
| */ |
| @Deprecated |
| public Template(String name, Reader reader, Configuration cfg, String encoding) throws IOException { |
| this(name, null, reader, cfg, encoding); |
| } |
| |
| /** |
| * Constructs a template from a character stream. Note that this is a relatively expensive operation; where higher |
| * performance matters, you should re-use (cache) {@link Template} instances instead of re-creating them from the |
| * same source again and again. ({@link Configuration#getTemplate(String) and its overloads already do such reuse.}) |
| * |
| * @param name |
| * The path of the template file relatively to the (virtual) directory that you use to store the |
| * templates (except if {@link #Template(String, String, Reader, Configuration, String) sourceName} |
| * differs from it). Shouldn't start with {@code '/'}. Should use {@code '/'}, not {@code '\'}. Check |
| * {@link #getName()} to see how the name will be used. The name should be independent of the actual |
| * storage mechanism and physical location as far as possible. Even when the templates are stored |
| * straightforwardly in real files (they often aren't; see {@link TemplateLoader}), the name shouldn't be |
| * an absolute file path. Like if the template is stored in {@code "/www/templates/forum/main.ftl"}, and |
| * you are using {@code "/www/templates/"} as the template root directory via |
| * {@link Configuration#setDirectoryForTemplateLoading(java.io.File)}, then the template name will be |
| * {@code "forum/main.ftl"}. The name can be {@code null} (should be used for template made on-the-fly |
| * instead of being loaded from somewhere), in which case relative paths in it will be relative to |
| * the template root directory (and here again, it's the {@link TemplateLoader} that knows what that |
| * "physically" means). |
| * @param sourceName |
| * See {@link #getSourceName()} for the meaning. Can be {@code null}, in which case |
| * {@link #getSourceName()} will return the same as {@link #getName()}. |
| * @param reader |
| * The character stream to read from. It will always be closed ({@link Reader#close()}) by this method. |
| * @param cfg |
| * The Configuration object that this Template is associated with. If this is {@code null}, the "default" |
| * {@link Configuration} object is used, which is highly discouraged, because it can easily lead to |
| * erroneous, unpredictable behavior. (See more {@link Configuration#getDefaultConfiguration() here...}) |
| * |
| * @since 2.3.22 |
| */ |
| public Template( |
| String name, String sourceName, Reader reader, Configuration cfg) throws IOException { |
| this(name, sourceName, reader, cfg, null); |
| } |
| |
| /** |
| * Same as {@link #Template(String, String, Reader, Configuration)}, but also specifies the template's encoding (not |
| * recommended). |
| * |
| * @param encoding |
| * This is the encoding that we are supposed to be using. But it's not really necessary because we have a |
| * {@link Reader} which is already decoded, but it's kept as meta-info. It also has an impact when |
| * {@code #include}-ing/{@code #import}-ing another template from this template, as its default encoding |
| * will be this. But this behavior of said directives is considered to be harmful, and will be probably |
| * phased out. Until that, it's better to leave this on {@code null}, so that the encoding will come from |
| * the {@link Configuration}. Note that if this is non-{@code null} and there's an {@code #ftl} header |
| * with encoding, they must match, or else a {@link WrongEncodingException} is thrown. |
| * |
| * @deprecated In most applications, use {@link #Template(String, String, Reader, Configuration)} instead, which |
| * doesn't specify the encoding. |
| * |
| * @since 2.3.22 |
| */ |
| @Deprecated |
| public Template( |
| String name, String sourceName, Reader reader, Configuration cfg, String encoding) throws IOException { |
| this(name, sourceName, reader, cfg, null, encoding); |
| } |
| |
| /** |
| * Same as {@link #Template(String, String, Reader, Configuration, String)}, but also specifies a |
| * {@link TemplateConfiguration}. This is mostly meant to be used by FreeMarker internally, but advanced users might |
| * still find this useful. |
| * |
| * @param customParserCfg |
| * Overrides the parsing related configuration settings of the {@link Configuration} parameter; can be |
| * {@code null}. This is useful as the {@link Configuration} is normally a singleton shared by all |
| * templates, and so it's not good for specifying template-specific settings. (While |
| * {@link Template} itself has methods to specify settings just for that template, those don't influence |
| * the parsing, and you only have opportunity to call them after the parsing anyway.) This objects is |
| * often a {@link TemplateConfiguration} whose parent is the {@link Configuration} parameter, and then it |
| * practically just overrides some of the parser settings, as the others are inherited from the |
| * {@link Configuration}. Note that if this is a {@link TemplateConfiguration}, you will also want to call |
| * {@link TemplateConfiguration#apply(Template)} on the resulting {@link Template} so that |
| * {@link Configurable} settings will be set too, because this constructor only uses it as a |
| * {@link ParserConfiguration}. |
| * @param encoding |
| * Same as in {@link #Template(String, String, Reader, Configuration, String)}. When it's non-{@code |
| * null}, it overrides the value coming from the {@code TemplateConfiguration#getEncoding()} method of the |
| * {@code templateConfigurer} parameter. |
| * |
| * @since 2.3.24 |
| */ |
| public Template( |
| String name, String sourceName, Reader reader, Configuration cfg, ParserConfiguration customParserCfg, |
| String encoding) throws IOException { |
| this( |
| _CoreAPI.newUnboundTemplate( |
| reader, |
| sourceName != null ? sourceName : name, |
| toNonNull(cfg), |
| customParserCfg, |
| encoding), |
| name, cfg); |
| this.encoding = encoding; |
| DebuggerService.registerTemplate(this); |
| } |
| |
| /** |
| * Equivalent to {@link #Template(String, Reader, Configuration) |
| * Template(name, reader, null)}. |
| * |
| * @deprecated This constructor uses the "default" {@link Configuration} |
| * instance, which can easily lead to erroneous, unpredictable behavior. |
| * See more {@link Configuration#getDefaultConfiguration() here...}. |
| */ |
| @Deprecated |
| public Template(String name, Reader reader) throws IOException { |
| this(name, reader, (Configuration) null); |
| } |
| |
| /** |
| * Same as {@link #getPlainTextTemplate(String, String, String, Configuration)} with {@code null} {@code sourceName} |
| * argument. |
| */ |
| static public Template getPlainTextTemplate(String name, String content, Configuration config) { |
| return getPlainTextTemplate(name, null, content, config); |
| } |
| |
| /** |
| * Creates (not "get"-s) a {@link Template} that only contains a single block of static text, no dynamic content. |
| * |
| * @param name |
| * See {@link #getName} for more details. |
| * @param sourceName |
| * See {@link #getSourceName} for more details. If {@code null}, it will be the same as the {@code name}. |
| * @param content |
| * the block of text that this template represents |
| * @param config |
| * the configuration to which this template belongs |
| * |
| * @since 2.3.22 |
| */ |
| static public Template getPlainTextTemplate(String name, String sourceName, String content, Configuration config) { |
| Template t = new Template( |
| _CoreAPI.newPlainTextUnboundTemplate(content, sourceName != null ? sourceName : name, config), |
| name, config); |
| DebuggerService.registerTemplate(t); |
| return t; |
| } |
| |
| /** |
| * Executes template, using the data-model provided, writing the generated output to the supplied {@link Writer}. |
| * |
| * <p> |
| * For finer control over the runtime environment setup, such as per-HTTP-request configuring of FreeMarker |
| * settings, you may need to use {@link #createProcessingEnvironment(Object, Writer)} instead. |
| * |
| * @param dataModel |
| * the holder of the variables visible from the template (name-value pairs); usually a |
| * {@code Map<String, Object>} or a JavaBean (where the JavaBean properties will be the variables). Can |
| * be any object that the {@link ObjectWrapper} in use turns into a {@link TemplateHashModel}. You can |
| * also use an object that already implements {@link TemplateHashModel}; in that case it won't be |
| * wrapped. If it's {@code null}, an empty data model is used. |
| * @param out |
| * The {@link Writer} where the output of the template will go. Note that unless you have used |
| * {@link Configuration#setAutoFlush(boolean)} to disable this, {@link Writer#flush()} will be called at |
| * the when the template processing was finished. {@link Writer#close()} is not called. Can't be |
| * {@code null}. |
| * |
| * @throws TemplateException |
| * if an exception occurs during template processing |
| * @throws IOException |
| * if an I/O exception occurs during writing to the writer. |
| */ |
| public void process(Object dataModel, Writer out) |
| throws TemplateException, IOException { |
| createProcessingEnvironment(dataModel, out, null).process(); |
| } |
| |
| /** |
| * Like {@link #process(Object, Writer)}, but also sets a (XML-)node to be recursively processed by the template. |
| * That node is accessed in the template with <tt>.node</tt>, <tt>#recurse</tt>, etc. See the |
| * <a href="http://freemarker.org/docs/xgui_declarative.html" target="_blank">Declarative XML Processing</a> as a |
| * typical example of recursive node processing. |
| * |
| * @param rootNode The root node for recursive processing or {@code null}. |
| * |
| * @throws TemplateException if an exception occurs during template processing |
| * @throws IOException if an I/O exception occurs during writing to the writer. |
| */ |
| public void process(Object dataModel, Writer out, ObjectWrapper wrapper, TemplateNodeModel rootNode) |
| throws TemplateException, IOException { |
| Environment env = createProcessingEnvironment(dataModel, out, wrapper); |
| if (rootNode != null) { |
| env.setCurrentVisitorNode(rootNode); |
| } |
| env.process(); |
| } |
| |
| /** |
| * Like {@link #process(Object, Writer)}, but overrides the {@link Configuration#getObjectWrapper()}. |
| * |
| * @param wrapper The {@link ObjectWrapper} to be used instead of what {@link Configuration#getObjectWrapper()} |
| * provides, or {@code null} if you don't want to override that. |
| */ |
| public void process(Object dataModel, Writer out, ObjectWrapper wrapper) |
| throws TemplateException, IOException { |
| createProcessingEnvironment(dataModel, out, wrapper).process(); |
| } |
| |
| /** |
| * Creates a {@link freemarker.core.Environment Environment} object, using this template, the data-model provided as |
| * parameter. You have to call {@link Environment#process()} on the return value to set off the actual rendering. |
| * |
| * <p>Use this method if you want to do some special initialization on the {@link Environment} before template |
| * processing, or if you want to read the {@link Environment} after template processing. Otherwise using |
| * {@link Template#process(Object, Writer)} is simpler. |
| * |
| * <p>Example: |
| * |
| * <pre> |
| * Environment env = myTemplate.createProcessingEnvironment(root, out, null); |
| * env.process();</pre> |
| * |
| * <p>The above is equivalent with this: |
| * |
| * <pre> |
| * myTemplate.process(root, out);</pre> |
| * |
| * <p>But with <tt>createProcessingEnvironment</tt>, you can manipulate the environment |
| * before and after the processing: |
| * |
| * <pre> |
| * Environment env = myTemplate.createProcessingEnvironment(root, out); |
| * |
| * env.setLocale(myUsersPreferredLocale); |
| * env.setTimeZone(myUsersPreferredTimezone); |
| * |
| * env.process(); // output is rendered here |
| * |
| * TemplateModel x = env.getVariable("x"); // read back a variable set by the template</pre> |
| * |
| * @param dataModel the holder of the variables visible from all templates; see {@link #process(Object, Writer)} for |
| * more details. |
| * @param wrapper The {@link ObjectWrapper} to use to wrap objects into {@link TemplateModel} |
| * instances. Normally you left it {@code null}, in which case {@link Configurable#getObjectWrapper()} will be |
| * used. |
| * @param out The {@link Writer} where the output of the template will go; see {@link #process(Object, Writer)} for |
| * more details. |
| * |
| * @return the {@link Environment} object created for processing. Call {@link Environment#process()} to process the |
| * template. |
| * |
| * @throws TemplateException if an exception occurs while setting up the Environment object. |
| * @throws IOException if an exception occurs doing any auto-imports |
| */ |
| public Environment createProcessingEnvironment(Object dataModel, Writer out, ObjectWrapper wrapper) |
| throws TemplateException, IOException { |
| final TemplateHashModel dataModelHash; |
| if (dataModel instanceof TemplateHashModel) { |
| dataModelHash = (TemplateHashModel) dataModel; |
| } else { |
| if (wrapper == null) { |
| wrapper = getObjectWrapper(); |
| } |
| |
| if (dataModel == null) { |
| dataModelHash = new SimpleHash(wrapper); |
| } else { |
| TemplateModel wrappedDataModel = wrapper.wrap(dataModel); |
| if (wrappedDataModel instanceof TemplateHashModel) { |
| dataModelHash = (TemplateHashModel) wrappedDataModel; |
| } else if (wrappedDataModel == null) { |
| throw new IllegalArgumentException( |
| wrapper.getClass().getName() + " converted " + dataModel.getClass().getName() + " to null."); |
| } else { |
| throw new IllegalArgumentException( |
| wrapper.getClass().getName() + " didn't convert " + dataModel.getClass().getName() |
| + " to a TemplateHashModel. Generally, you want to use a Map<String, Object> or a " |
| + "JavaBean as the root-map (aka. data-model) parameter. The Map key-s or JavaBean " |
| + "property names will be the variable names in the template."); |
| } |
| } |
| } |
| return new Environment(this, dataModelHash, out); |
| } |
| |
| /** |
| * Same as {@link #createProcessingEnvironment(Object, Writer, ObjectWrapper) |
| * createProcessingEnvironment(dataModel, out, null)}. |
| */ |
| public Environment createProcessingEnvironment(Object dataModel, Writer out) |
| throws TemplateException, IOException { |
| return createProcessingEnvironment(dataModel, out, null); |
| } |
| |
| /** |
| * Returns a string representing the raw template |
| * text in canonical form. |
| */ |
| @Override |
| public String toString() { |
| StringWriter sw = new StringWriter(); |
| try { |
| dump(sw); |
| } catch (IOException ioe) { |
| throw new RuntimeException(ioe.getMessage()); |
| } |
| return sw.toString(); |
| } |
| |
| /** |
| * Returns the {@link UnboundTemplate} that this {@link Template} is based on. |
| * |
| * @since 2.4.0 |
| */ |
| public UnboundTemplate getUnboundTemplate() { |
| return unboundTemplate; |
| } |
| |
| /** |
| * The usually path-like (or URL-like) identifier of the template, or possibly {@code null} for non-stored |
| * templates. It usually looks like a relative UN*X path; it should use {@code /}, not {@code \}, and shouldn't |
| * start with {@code /} (but there are no hard guarantees). It's not a real path in a file-system, it's just a name |
| * that a {@link TemplateLoader} used to load the backing resource (in simple cases; actually that name is |
| * {@link #getSourceName()}, but see it there). Or, it can also be a name that was never used to load the template |
| * (directly created with {@link #Template(String, Reader, Configuration)}). Even if the templates are stored |
| * straightforwardly in files, this is relative to the base directory of the {@link TemplateLoader}. So it really |
| * could be anything, except that it has importance in these situations: |
| * |
| * <p> |
| * Relative paths to other templates in this template will be resolved relatively to the directory part of this. |
| * Like if the template name is {@code "foo/this.ftl"}, then {@code <#include "other.ftl">} gets the template with |
| * name {@code "foo/other.ftl"}. |
| * </p> |
| * |
| * <p> |
| * You should not use this name to indicate error locations, or to find the actual templates in general, because |
| * localized lookup, acquisition and other lookup strategies can transform names before they get to the |
| * {@link TemplateLoader} (the template storage) mechanism. Use {@link #getSourceName()} for these purposes. |
| * </p> |
| * |
| * <p> |
| * Some frameworks use URL-like template names like {@code "someSchema://foo/bar.ftl"}. FreeMarker understands this |
| * notation, so an absolute path like {@code "/baaz.ftl"} in that template will be resolved too |
| * {@code "someSchema://baaz.ftl"}. |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * The name that was actually used to load this template from the {@link TemplateLoader} (or from other custom |
| * storage mechanism). This is what should be shown in error messages as the error location. This is usually the |
| * same as {@link #getName()}, except when localized lookup, template acquisition ({@code *} step in the name), or |
| * other {@link TemplateLookupStrategy} transforms the requested name ({@link #getName()}) to a different final |
| * {@link TemplateLoader}-level name. For example, when you get a template with name {@code "foo.ftl"} then because |
| * of localized lookup, it's possible that something like {@code "foo_en.ftl"} will be loaded behind the scenes. |
| * While the template name will be still the same as the requested template name ({@code "foo.ftl"}), errors should |
| * point to {@code "foo_de.ftl"}. Note that relative paths are always resolved relatively to the {@code name}, not |
| * to the {@code sourceName}. |
| * |
| * @since 2.3.22 |
| */ |
| public String getSourceName() { |
| return unboundTemplate.getSourceName(); |
| } |
| |
| /** |
| * Returns the Configuration object associated with this template. |
| */ |
| public Configuration getConfiguration() { |
| return (Configuration) getParent(); |
| } |
| |
| /** |
| * Returns the {@link ParserConfiguration} that was used for parsing this template. This is most often the same |
| * object as {@link #getConfiguration()}, but sometimes it's a {@link TemplateConfiguration}, or something else. It's |
| * never {@code null}. |
| * |
| * @since 2.3.24 |
| */ |
| public ParserConfiguration getParserConfiguration() { |
| return unboundTemplate.getParserConfiguration(); |
| } |
| |
| /** |
| * Return the template language (FTL) version used by this template. |
| * For now (2.4.0) this is the same as {@link Configuration#getIncompatibleImprovements()}, except |
| * that it's normalized to the lowest version where the template language was changed. |
| * |
| * @since 2.4.0 |
| */ |
| public Version getTemplateLanguageVersion() { |
| return unboundTemplate.getTemplateLanguageVersion(); |
| } |
| |
| /** |
| * @param encoding |
| * The encoding that was used to read this template. When this template {@code #include}-s or |
| * {@code #import}-s another template, by default it will use this encoding for those. For backward |
| * compatibility, this can be {@code null}, which will unset this setting. |
| * |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public void setEncoding(String encoding) { |
| this.encoding = encoding; |
| } |
| |
| /** |
| * Returns the name of the charset used for reading included/imported template files by default. |
| * |
| * <p> |
| * At least when FreeMarker is built-in template loading mechanism is used, by default this setting is set to the |
| * same value as the {@link UnboundTemplate#getTemplateSpecifiedEncoding()} of the wrapped {@link UnboundTemplate}, |
| * if that's non-{@code null}. |
| * |
| * <p> |
| * While "inheriting" charset from the referring template is not seen as a good idea anymore, it's still used by |
| * FreeMarker for backward compatibility (at least by default; as of 2.3.22 no setting exists yet to change that). |
| */ |
| public String getEncoding() { |
| return this.encoding; |
| } |
| |
| /** |
| * Gets the custom lookup condition with which this template was found. See the {@code customLookupCondition} |
| * parameter of {@link Configuration#getTemplate(String, java.util.Locale, Object, String, boolean, boolean)} for |
| * more explanation. |
| * |
| * @since 2.3.22 |
| */ |
| public Object getCustomLookupCondition() { |
| return customLookupCondition; |
| } |
| |
| /** |
| * Mostly only used internally; setter pair of {@link #getCustomLookupCondition()}. This meant to be called directly |
| * after instantiating the template with its constructor, after a successfull lookup that used this condition. So |
| * this should only be called from code that deals with creating new {@code Template} objects, like from |
| * {@link TemplateCache}. |
| * |
| * @since 2.3.22 |
| */ |
| public void setCustomLookupCondition(Object customLookupCondition) { |
| this.customLookupCondition = customLookupCondition; |
| } |
| |
| /** |
| * Returns the tag syntax the parser has chosen for this template. If the syntax could be determined, it's |
| * {@link Configuration#SQUARE_BRACKET_TAG_SYNTAX} or {@link Configuration#ANGLE_BRACKET_TAG_SYNTAX}. If the syntax |
| * couldn't be determined (like because there was no tags in the template, or it was a plain text template), this |
| * returns whatever the default is in the current configuration, so it's maybe |
| * {@link Configuration#AUTO_DETECT_TAG_SYNTAX}. |
| * |
| * @since 2.3.20 |
| */ |
| public int getActualTagSyntax() { |
| return unboundTemplate.getActualTagSyntax(); |
| } |
| |
| /** |
| * Returns the naming convention the parser has chosen for this template. If it could be determined, it's |
| * {@link Configuration#LEGACY_NAMING_CONVENTION} or {@link Configuration#CAMEL_CASE_NAMING_CONVENTION}. If it |
| * couldn't be determined (like because there no identifier that's part of the template language was used where |
| * the naming convention matters), this returns whatever the default is in the current configuration, so it's maybe |
| * {@link Configuration#AUTO_DETECT_TAG_SYNTAX}. |
| * |
| * @since 2.3.23 |
| */ |
| public int getActualNamingConvention() { |
| return unboundTemplate.getActualNamingConvention(); |
| } |
| |
| /** |
| * Returns the output format (see {@link Configuration#setOutputFormat(OutputFormat)}) used for this template. |
| * The output format of a template can come from various places, in order of increasing priority: |
| * {@link Configuration#getOutputFormat()}, {@link ParserConfiguration#getOutputFormat()} (which is usually |
| * provided by {@link Configuration#getTemplateConfigurations()}) and the {@code #ftl} header's {@code output_format} |
| * option in the template. |
| * |
| * @since 2.3.24 |
| */ |
| public OutputFormat getOutputFormat() { |
| return unboundTemplate.getOutputFormat(); |
| } |
| |
| /** |
| * Returns if the template actually uses auto-escaping (see {@link Configuration#setAutoEscapingPolicy(int)}). This value |
| * is decided by the parser based on the actual {@link OutputFormat}, and the auto-escaping enums, in order of |
| * increasing priority: {@link Configuration#getAutoEscapingPolicy()}, {@link ParserConfiguration#getAutoEscapingPolicy()} |
| * (which is usually provided by {@link Configuration#getTemplateConfigurations()}), and finally on the {@code #ftl} |
| * header's {@code auto_esc} option in the template. |
| * |
| * @since 2.3.24 |
| */ |
| public boolean getAutoEscaping() { |
| return unboundTemplate.getAutoEscaping(); |
| } |
| |
| /** |
| * Dump the raw template in canonical form. |
| */ |
| public void dump(PrintStream ps) { |
| unboundTemplate.dump(ps); |
| } |
| |
| /** |
| * Dump the raw template in canonical form. |
| */ |
| public void dump(Writer out) throws IOException { |
| unboundTemplate.dump(out); |
| } |
| |
| /** |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public void addMacro(Macro macro) { |
| _CoreAPI.addMacro(unboundTemplate, macro); |
| } |
| |
| /** |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public void addImport(LibraryLoad libLoad) { |
| _CoreAPI.addImport(unboundTemplate, libLoad); |
| } |
| |
| /** |
| * Returns the template source at the location specified by the coordinates given, or {@code null} if unavailable. |
| * @param beginColumn the first column of the requested source, 1-based |
| * @param beginLine the first line of the requested source, 1-based |
| * @param endColumn the last column of the requested source, 1-based |
| * @param endLine the last line of the requested source, 1-based |
| * @see freemarker.core.TemplateObject#getSource() |
| */ |
| public String getSource(int beginColumn, int beginLine, int endColumn, int endLine) { |
| return unboundTemplate.getSource(beginColumn, beginLine, endColumn, endLine); |
| } |
| |
| /** |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public TemplateElement getRootTreeNode() { |
| return _CoreAPI.getRootTreeNode(unboundTemplate); |
| } |
| |
| /** |
| * For 2.3 backward compatibility. Initialized on demand. |
| */ |
| private volatile Map<String, Macro> legacyMacroMap; |
| |
| /** |
| * Returns the {@link Map} that maps the macro names to the actual macros. This map shouldn't be modified; if you |
| * absolutely has to use these deprecated API-s for adding a macro, at least use {@link #addMacro(Macro)}. |
| * (Specifying the {@link Map} key has no purpose anyway, as the macro will be always defined with its original |
| * name, as returned by {@link Macro#getName()}.) |
| * |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public Map getMacros() { |
| Map<String, Macro> legacyMacroMap = this.legacyMacroMap; |
| if (legacyMacroMap == null) { |
| synchronized (this) { |
| legacyMacroMap = this.legacyMacroMap; |
| if (legacyMacroMap == null) { |
| legacyMacroMap = _CoreAPI.createAdapterMacroMapForUnboundCallables(unboundTemplate); |
| this.legacyMacroMap = legacyMacroMap; |
| } |
| } |
| } |
| return legacyMacroMap; |
| } |
| |
| /** |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public List getImports() { |
| return _CoreAPI.getImports(unboundTemplate); |
| } |
| |
| /** |
| * This is used internally. |
| * |
| * @deprecated Should only be used internally, and might will be removed later. |
| */ |
| @Deprecated |
| public void addPrefixNSMapping(String prefix, String nsURI) { |
| _CoreAPI.addPrefixNSMapping(unboundTemplate, prefix, nsURI); |
| } |
| |
| public String getDefaultNS() { |
| return unboundTemplate.getDefaultNamespaceURI(); |
| } |
| |
| /** |
| * @return the NamespaceUri mapped to this prefix in this template. (Or null if there is none.) |
| */ |
| public String getNamespaceForPrefix(String prefix) { |
| return unboundTemplate.getNamespaceURIForPrefix(prefix); |
| } |
| |
| /** |
| * @return the prefix mapped to this nsURI in this template. (Or null if there is none.) |
| */ |
| public String getPrefixForNamespace(String nsURI) { |
| return unboundTemplate.getPrefixForNamespaceURI(nsURI); |
| } |
| |
| /** |
| * @return the prefixed name, based on the ns_prefixes defined |
| * in this template's header for the local name and node namespace |
| * passed in as parameters. |
| */ |
| public String getPrefixedName(String localName, String nsURI) { |
| return unboundTemplate.getPrefixedName(localName, nsURI); |
| } |
| |
| /** |
| * @return an array of the {@link TemplateElement}s containing the given column and line numbers. |
| * @deprecated Should only be used internally, and might will be removed later. |
| * |
| * @deprecated The objects building up templates aren't part of the published API, and are subject to change. |
| */ |
| @Deprecated |
| public List containingElements(int column, int line) { |
| return _CoreAPI.containingElements(unboundTemplate, column, line); |
| } |
| |
| @Override |
| protected Map<String, ?> getInitialCustomAttributes() { |
| return _CoreAPI.getCustomAttributes(unboundTemplate); |
| } |
| |
| /** |
| * Thrown by the {@link Template} constructors that specify a non-{@code null} encoding which doesn't match the |
| * encoding specified in the {@code #ftl} header of the template. |
| */ |
| static public class WrongEncodingException extends ParseException { |
| private static final long serialVersionUID = 1L; |
| |
| /** @deprecated Use {@link #getTemplateSpecifiedEncoding()} instead. */ |
| @Deprecated |
| public String specifiedEncoding; |
| |
| private final String constructorSpecifiedEncoding; |
| |
| /** |
| * @deprecated Use {@link #WrongEncodingException(String, String)}. |
| */ |
| @Deprecated |
| public WrongEncodingException(String templateSpecifiedEncoding) { |
| this(templateSpecifiedEncoding, null); |
| } |
| |
| /** |
| * @since 2.3.22 |
| */ |
| public WrongEncodingException(String templateSpecifiedEncoding, String constructorSpecifiedEncoding) { |
| this.specifiedEncoding = templateSpecifiedEncoding; |
| this.constructorSpecifiedEncoding = constructorSpecifiedEncoding; |
| } |
| |
| @Override |
| public String getMessage() { |
| return "Encoding specified inside the template (" + specifiedEncoding |
| + ") doesn't match the encoding specified for the Template constructor" |
| + (constructorSpecifiedEncoding != null ? " (" + constructorSpecifiedEncoding + ")." : "."); |
| } |
| |
| /** |
| * @since 2.3.22 |
| */ |
| public String getTemplateSpecifiedEncoding() { |
| return specifiedEncoding; |
| } |
| |
| /** |
| * @since 2.3.22 |
| */ |
| public String getConstructorSpecifiedEncoding() { |
| return constructorSpecifiedEncoding; |
| } |
| |
| } |
| |
| } |