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

freemarker.core.CustomAttribute Maven / Gradle / Ivy

There is a newer version: 7.0.58
Show newest version
/*
 * 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.core;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * A class that allows one to associate custom data with a {@link Configuration}, a {@link Template}, or
 * {@link Environment}.
 * 
 * 

This API has similar approach to that of {@link ThreadLocal} (which allows one to associate * custom data with a thread). With an example:

* *
 * // The object identity itself will serve as the attribute identifier; there's no attribute name String:
 * public static final CustomAttribute MY_ATTR = new CustomAttribute(CustomAttribute.SCOPE_CONFIGURATION);
 * ...
 *     // Set the attribute in this particular Configuration object:
 *     MY_ATTR.set(myAttrValue, cfg);
 *     ...
 *     // Read the attribute from this particular Configuration object:
 *     myAttrValue = MY_ATTR.get(cfg);
 * 
*/ // [2.4] Use generics; type parameter used for the type of the stored value public class CustomAttribute { /** * Constant used in the constructor specifying that this attribute is {@link Environment}-scoped. */ public static final int SCOPE_ENVIRONMENT = 0; /** * Constant used in the constructor specifying that this attribute is {@link Template}-scoped. */ public static final int SCOPE_TEMPLATE = 1; /** * Constant used in the constructor specifying that this attribute is {@link Configuration}-scoped. */ public static final int SCOPE_CONFIGURATION = 2; // We use an internal key instead of 'this' so that malicious subclasses // overriding equals() and hashCode() can't gain access to other attribute // values. That's also the reason why get() and set() are marked final. private final Object key = new Object(); private final int scope; /** * Creates a new custom attribute with the specified scope * @param scope one of SCOPE_ constants. */ public CustomAttribute(int scope) { if (scope != SCOPE_ENVIRONMENT && scope != SCOPE_TEMPLATE && scope != SCOPE_CONFIGURATION) { throw new IllegalArgumentException(); } this.scope = scope; } /** * This method is invoked when {@link #get()} is invoked without * {@link #set(Object)} being invoked before it to define the value in the * current scope. Override it to create the attribute value on-demand. * @return the initial value for the custom attribute. By default returns null. */ protected Object create() { return null; } /** * Gets the attribute from the appropriate scope that's accessible through the specified {@link Environment}. If * the attribute has {@link #SCOPE_ENVIRONMENT} scope, it will be get from the given {@link Environment} directly. * If the attribute has {@link #SCOPE_TEMPLATE} scope, it will be get from the parent of the given * {@link Environment} (that is, in {@link Environment#getParent()}) directly). If the attribute has * {@link #SCOPE_CONFIGURATION} scope, it will be get from {@link Environment#getConfiguration()}. * * @throws NullPointerException * If {@code env} is null * * @return The new value of the attribute (possibly {@code null}), or {@code null} if the attribute doesn't exist. * * @since 2.3.22 */ public final Object get(Environment env) { return getScopeConfigurable(env).getCustomAttribute(key, this); } /** * Same as {@link #get(Environment)}, but uses {@link Environment#getCurrentEnvironment()} to fill the 2nd argument. * * @throws IllegalStateException * If there is no current {@link Environment}, which is usually the case when the current thread isn't * processing a template. */ public final Object get() { return getScopeConfigurable(getRequiredCurrentEnvironment()).getCustomAttribute(key, this); } /** * Gets the value of a {@link Template}-scope attribute from the given {@link Template}. * * @throws UnsupportedOperationException * If this custom attribute has different scope than {@link #SCOPE_TEMPLATE}. * @throws NullPointerException * If {@code template} is null */ public final Object get(Template template) { if (scope != SCOPE_TEMPLATE) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } return ((Configurable) template).getCustomAttribute(key, this); } /** * Same as {@link #get(Template)}, but applies to a {@link TemplateConfiguration}. * * @since 2.3.24 */ public Object get(TemplateConfiguration templateConfiguration) { if (scope != SCOPE_TEMPLATE) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } return templateConfiguration.getCustomAttribute(key, this); } /** * Gets the value of a {@link Configuration}-scope attribute from the given {@link Configuration}. * * @throws UnsupportedOperationException * If this custom attribute has different scope than {@link #SCOPE_CONFIGURATION}. * @throws NullPointerException * If {@code cfg} is null * * @since 2.3.22 */ public final Object get(Configuration cfg) { if (scope != SCOPE_CONFIGURATION) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } return ((Configurable) cfg).getCustomAttribute(key, this); } /** * Sets the attribute inside the appropriate scope that's accessible through the specified {@link Environment}. If * the attribute has {@link #SCOPE_ENVIRONMENT} scope, it will be set in the given {@link Environment} directly. If * the attribute has {@link #SCOPE_TEMPLATE} scope, it will be set in the parent of the given {@link Environment} * (that is, in {@link Environment#getParent()}) directly). If the attribute has {@link #SCOPE_CONFIGURATION} scope, * it will be set in {@link Environment#getConfiguration()}. * * @param value * The new value of the attribute. Can be {@code null}. * * @throws NullPointerException * If {@code env} is null * * @since 2.3.22 */ public final void set(Object value, Environment env) { getScopeConfigurable(env).setCustomAttribute(key, value); } /** * Same as {@link #set(Object, Environment)}, but uses {@link Environment#getCurrentEnvironment()} to fill the 2nd * argument. * * @throws IllegalStateException * If there is no current {@link Environment}, which is usually the case when the current thread isn't * processing a template. */ public final void set(Object value) { getScopeConfigurable(getRequiredCurrentEnvironment()).setCustomAttribute(key, value); } /** * Sets the value of a {@link Template}-scope attribute in the given {@link Template}. * * @param value * The new value of the attribute. Can be {@code null}. * * @throws UnsupportedOperationException * If this custom attribute has different scope than {@link #SCOPE_TEMPLATE}. * @throws NullPointerException * If {@code template} is null */ public final void set(Object value, Template template) { if (scope != SCOPE_TEMPLATE) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } ((Configurable) template).setCustomAttribute(key, value); } /** * Same as {@link #set(Object, Template)}, but applicable to a {@link TemplateConfiguration}. * * @since 2.3.24 */ public final void set(Object value, TemplateConfiguration templateConfiguration) { if (scope != SCOPE_TEMPLATE) { throw new UnsupportedOperationException("This is not a template-scope attribute"); } templateConfiguration.setCustomAttribute(key, value); } /** * Sets the value of a {@link Configuration}-scope attribute in the given {@link Configuration}. * * @param value * The new value of the attribute. Can be {@code null}. * * @throws UnsupportedOperationException * If this custom attribute has different scope than {@link #SCOPE_CONFIGURATION}. * @throws NullPointerException * If {@code cfg} is null * * @since 2.3.22 */ public final void set(Object value, Configuration cfg) { if (scope != SCOPE_CONFIGURATION) { throw new UnsupportedOperationException("This is not a configuration-scope attribute"); } ((Configurable) cfg).setCustomAttribute(key, value); } private Environment getRequiredCurrentEnvironment() { Environment c = Environment.getCurrentEnvironment(); if (c == null) { throw new IllegalStateException("No current environment"); } return c; } private Configurable getScopeConfigurable(Environment env) throws Error { switch (scope) { case SCOPE_ENVIRONMENT: return env; case SCOPE_TEMPLATE: return env.getParent(); case SCOPE_CONFIGURATION: return env.getParent().getParent(); default: throw new BugException(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy