org.thymeleaf.templateresolver.AbstractTemplateResolver Maven / Gradle / Ivy
Show all versions of thymeleaf Show documentation
/*
* =============================================================================
*
* Copyright (c) 2011-2016, The THYMELEAF team (http://www.thymeleaf.org)
*
* Licensed 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 org.thymeleaf.templateresolver;
import java.util.Map;
import java.util.Set;
import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.cache.ICacheEntryValidity;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.util.PatternSpec;
import org.thymeleaf.util.Validate;
/**
*
* Convenience base class for all Template Resolvers.
*
*
* Note a class with this name existed since 1.0, but it was completely reimplemented
* in Thymeleaf 3.0
*
*
* @author Daniel Fernández
*
* @since 3.0.0
*
*/
public abstract class AbstractTemplateResolver implements ITemplateResolver {
/**
*
* By default, resources will not be checked their existence before being returned. This tries to
* avoid a possible performance impact from performing a double access to the resource (one for checking
* existence, another one for reading it).
*
*/
public static final boolean DEFAULT_EXISTENCE_CHECK = false;
/**
*
* By default, resources will not be marked to look for decoupled logic.
*
*/
public static final boolean DEFAULT_USE_DECOUPLED_LOGIC = false;
private String name = this.getClass().getName();
private Integer order = null;
private boolean checkExistence = DEFAULT_EXISTENCE_CHECK;
private boolean useDecoupledLogic = DEFAULT_USE_DECOUPLED_LOGIC;
private final PatternSpec resolvablePatternSpec = new PatternSpec();
protected AbstractTemplateResolver() {
super();
}
/**
*
* Returns the name of the template resolver
*
*
* @return the name of the template resolver
*/
public final String getName() {
return this.name;
}
/**
*
* Sets a new name for the Template Resolver.
*
*
* @param name the new name
*/
public void setName(final String name) {
this.name = name;
}
/**
*
* Returns the order in which this template resolver will be asked to resolve
* templates as a part of the chain of resolvers configured into the template engine.
*
*
* Order should start with 1.
*
*
* @return the order in which this template resolver will be called in the chain.
*/
public final Integer getOrder() {
return this.order;
}
/**
*
* Sets a new order for the template engine in the chain. Order should start with 1.
*
*
* @param order the new order.
*/
public void setOrder(final Integer order) {
this.order = order;
}
/**
*
* Returns the pattern spec specified for establishing which
* templates can be resolved by this template resolver. For those templates
* which names do not match this patterns, the Template Resolver will return null.
*
*
* This allows for a fast discard of those templates that the developer might
* know for sure that will not be resolvable by the Resource Resolver used by
* this Template Resolver, so that an execution of the resource resolver is not needed.
*
*
* @return the pattern spec
*/
public final PatternSpec getResolvablePatternSpec() {
return this.resolvablePatternSpec;
}
/**
*
* Returns the patterns (as String) specified for establishing which
* templates can be resolved by this template resolver. For those templates
* which names do not match this patterns, the Template Resolver will return null.
*
*
* This allows for a fast discard of those templates that the developer might
* know for sure that will not be resolvable by the Resource Resolver used by
* this Template Resolver, so that an execution of the resource resolver is not needed.
*
*
* This is a convenience method equivalent to {@link #getResolvablePatternSpec()}.getPatterns()
*
*
* @return the pattern spec
*/
public final Set getResolvablePatterns() {
return this.resolvablePatternSpec.getPatterns();
}
/**
*
* Sets the new patterns to be applied for establishing which
* templates can be resolved by this template resolver. For those templates
* which names do not match this patterns, the Template Resolver will return null.
*
*
* This allows for a fast discard of those templates that the developer might
* know for sure that will not be resolvable by the Resource Resolver used by
* this Template Resolver, so that an execution of the resource resolver is not needed.
*
*
* This is a convenience method equivalent to {@link #getResolvablePatternSpec()}.setPatterns(Set<String>)
*
*
* @param resolvablePatterns the new patterns
*/
public void setResolvablePatterns(final Set resolvablePatterns) {
this.resolvablePatternSpec.setPatterns(resolvablePatterns);
}
/**
*
* Returns whether template resources will be checked for existence before being returned or not.
*
*
* Default value is FALSE.
*
*
* Checking resources for existence will make the template resolver execute {@link ITemplateResource#exists()}
* for each resolved resource before returning a {@link TemplateResolution}, returning null if the
* resource does not exist.
*
*
* This allows resolvers to pass control to the next {@link ITemplateResolver} in
* the chain based on real resource existence and not only on the matching performed by the resolvable
* patterns specified at {@link #getResolvablePatterns()}. But at the same time, might pose a performance
* issue on certain scenarios (e.g. HTTP URL resolution) that require actually accessing the resource in order
* to determine its existence, being the resource accessed twice in those cases (once for determining its
* existence, another time for reading it).
*
*
* If this existence check is enabled and a resource is determined to not exist,
* {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, String, String, Map)} will return null.
*
*
* @return true if resource existence will be checked, false if not
*
* @since 3.0.0
*
*/
public final boolean getCheckExistence() {
return this.checkExistence;
}
/**
*
* Sets whether template resources will be checked for existence before being returned or not.
*
*
* Default value is FALSE.
*
*
* Checking resources for existence will make the template resolver execute {@link ITemplateResource#exists()}
* for each resolved resource before returning a {@link TemplateResolution}, returning null if the
* resource does not exist.
*
*
* This allows resolvers to pass control to the next {@link ITemplateResolver} in
* the chain based on real resource existence and not only on the matching performed by the resolvable
* patterns specified at {@link #getResolvablePatterns()}. But at the same time, might pose a performance
* issue on certain scenarios (e.g. HTTP URL resolution) that require actually accessing the resource in order
* to determine its existence, being the resource accessed twice in those cases (once for determining its
* existence, another time for reading it).
*
*
* If this existence check is enabled and a resource is determined to not exist,
* {@link ITemplateResolver#resolveTemplate(IEngineConfiguration, String, String, Map)} will return null.
*
*
* @param checkExistence true if resource existence should be checked, false if not
*
* @since 3.0.0
*
*/
public void setCheckExistence(final boolean checkExistence) {
this.checkExistence = checkExistence;
}
/**
*
* Returns whether a separate (decoupled) resource containing template logic should be checked for existence
* and its instructions included into the resolved template during parsing.
*
*
* This mechanism allows the creation of pure HTML or XML markup templates, which acquire their logic
* from an external resource. The way this decoupled resources are resolved is defined by a configured
* implementation of the {@link org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver}
* interface.
*
*
* Note this flag can only be true for the {@link TemplateMode#HTML} and {@link TemplateMode#XML}
* template modes. Also, note that setting this flag to true does not mean that a resource with
* decoupled logic must exist for the resolved template, only that it can exist.
*
*
* Decoupled logic extracted from these additional resources is injected into the resolved templates in real-time
* as the resolved templates are parsed and processed. This greatly reduces overhead caused by decoupled parsing
* for non-cacheable templates, and completely removes any overhead for cached templates.
*
*
* Default value is FALSE.
*
*
* @return true if decoupled logic resources should be checked, false if not.
*
* @since 3.0.0
*
*/
public final boolean getUseDecoupledLogic() {
return this.useDecoupledLogic;
}
/**
*
* Sets whether a separate (decoupled) resource containing template logic should be checked for existence
* and its instructions included into the resolved template during parsing.
*
*
* This mechanism allows the creation of pure HTML or XML markup templates, which acquire their logic
* from an external resource. The way this decoupled resources are resolved is defined by a configured
* implementation of the {@link org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver}
* interface.
*
*
* Note this flag can only be true for the {@link TemplateMode#HTML} and {@link TemplateMode#XML}
* template modes. Also, note that setting this flag to true does not mean that a resource with
* decoupled logic must exist for the resolved template, only that it can exist and therefore it should be
* checked.
*
*
* Decoupled logic extracted from these additional resources is injected into the resolved templates in real-time
* as the resolved templates are parsed and processed. This greatly reduces overhead caused by decoupled parsing
* for non-cacheable templates, and completely removes any overhead for cached templates.
*
*
* Default value is FALSE.
*
*
* @param useDecoupledLogic true if resource existence should be checked, false if not
*
* @since 3.0.0
*
*/
public void setUseDecoupledLogic(final boolean useDecoupledLogic) {
this.useDecoupledLogic = useDecoupledLogic;
}
public final TemplateResolution resolveTemplate(
final IEngineConfiguration configuration,
final String ownerTemplate, final String template,
final Map templateResolutionAttributes) {
Validate.notNull(configuration, "Engine Configuration cannot be null");
// ownerTemplate CAN be null
Validate.notNull(template, "Template Name cannot be null");
// templateResolutionAttributes CAN be null
if (!computeResolvable(configuration, ownerTemplate, template, templateResolutionAttributes)) {
return null;
}
final ITemplateResource templateResource = computeTemplateResource(configuration, ownerTemplate, template, templateResolutionAttributes);
if (templateResource == null) {
return null;
}
if (this.checkExistence && !templateResource.exists()) { // will only check if flag set to true
return null;
}
return new TemplateResolution(
templateResource,
this.checkExistence,
computeTemplateMode(configuration, ownerTemplate, template, templateResolutionAttributes),
this.useDecoupledLogic,
computeValidity(configuration, ownerTemplate, template, templateResolutionAttributes));
}
/**
*
* Computes whether a template can be resolved by this resolver or not,
* applying the corresponding patterns. Meant only for use or override by subclasses.
*
*
* @param configuration the engine configuration.
* @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
* @param template the template to be resolved (usually its name).
* @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
*
* @return whether the template is resolvable or not.
*/
protected boolean computeResolvable(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map templateResolutionAttributes) {
if (this.resolvablePatternSpec.isEmpty()) {
return true;
}
return this.resolvablePatternSpec.matches(template);
}
/**
*
* Computes the resolved template resource.
*
*
* @param configuration the engine configuration.
* @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
* @param template the template to be resolved (usually its name).
* @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
*
* @return the template resource, or null if this template cannot be resolved (or the resource does not exist).
*/
protected abstract ITemplateResource computeTemplateResource(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map templateResolutionAttributes);
/**
*
* Computes the template mode that should be applied to a template, according
* to existing configuration.
*
*
* @param configuration the engine configuration.
* @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
* @param template the template to be resolved (usually its name).
* @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
*
* @return the template mode proposed by the template resolver for the resolved template.
*/
protected abstract TemplateMode computeTemplateMode(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map templateResolutionAttributes);
/**
*
* Computes the validity to be applied to the template resolution. This
* includes determining whether the template can be cached or not, and
* also in what circumstances (for instance, for how much time) can
* its cache entry be considered valid.
*
*
* @param configuration the engine configuration.
* @param ownerTemplate the owner template, if the resource being computed is a fragment. Might be null.
* @param template the template to be resolved (usually its name).
* @param templateResolutionAttributes the template resolution attributes, if any. Might be null.
* @return the validity
*/
protected abstract ICacheEntryValidity computeValidity(final IEngineConfiguration configuration, final String ownerTemplate, final String template, final Map templateResolutionAttributes);
}