org.thymeleaf.TemplateSpec 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;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.util.ContentTypeUtils;
import org.thymeleaf.util.LoggingUtils;
import org.thymeleaf.util.Validate;
/**
*
* Specification class containing everything needed by the template engine related to the
* template to be processed. Objects of this class are normally used as an argument to the
* different process(...) methods at {@link ITemplateEngine}.
*
*
* The only required value in a template specification is the template, which normally
* represents the template name, but can be the entire template contents if the template
* is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* This is not to be mistaken for the template processing context, containing
* the data to be used during the processing of the template (variables, locale, etc.) and
* modelled by the {@link org.thymeleaf.context.IContext} interface.
*
*
* The data contained in a Template Specification relates to and identifies the template itself,
* independently of any data (variables, etc.) used for processing it.
*
*
* Objects of this class are thread-safe.
*
*
* @author Daniel Fernández
*
* @since 3.0.0
*
*/
public final class TemplateSpec implements Serializable {
private static final long serialVersionUID = 51214133L;
private final String template;
private final Set templateSelectors;
private final TemplateMode templateMode;
private final Map templateResolutionAttributes;
private final String outputContentType;
private final boolean outputSSE;
/**
*
* Build a new object of this class, specifying template and also template mode.
*
*
* The template normally represents the template name, but can be the entire template
* contents if the template is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* The template mode only needs to be specified in cases when we want to force a template
* mode to be used for a template, independently of the mode that is selected for it by the configured
* template resolvers.
*
*
* This constructor will set no template selectors or template resolution attributes.
*
*
* @param template the template (usually the template name), required.
* @param templateMode the template mode to be forced, can be null.
*/
public TemplateSpec(final String template, final TemplateMode templateMode) {
this(template, null, templateMode, null, null);
}
/**
*
* Build a new object of this class, specifying template and also output content type
* (MIME type). Most of the times this will force a template mode for template execution
* (e.g. text/html, application/javascript), but not always (e.g. text/event-stream).
*
*
* The template normally represents the template name, but can be the entire template
* contents if the template is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* Supported relations between template mode and output content type are:
*
*
* - HTML: text/html, application/xhtml+xml
* - XML: application/xml
* - JAVASCRIPT: application/javascript, application/x-javascript,
* application/ecmascript, text/javascript,
* text/ecmascript, application/json
* - CSS: text/css
* - TEXT: text/plain
*
*
* The text/event-stream content type will also be supported, but will have no effect in
* forcing a template mode. Instead, it will put the engine into Server-Sent Event (SSE) output mode.
*
*
* Note content type parameters will be ignored (only the mime type itself will be used).
*
*
* This constructor will set no template selectors or template resolution attributes.
*
*
* @param template the template (usually the template name), required.
* @param outputContentType the expected output content type, can be null.
*
* @since 3.0.6
*/
public TemplateSpec(final String template, final String outputContentType) {
this(template, null, null, outputContentType, null);
}
/**
*
* Build a new object of this class, specifying template and also template mode.
*
*
* The template normally represents the template name, but can be the entire template
* contents if the template is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* The template resolution attributes are meant to be passed to the template resolvers (see
* {@link org.thymeleaf.templateresolver.ITemplateResolver} during template resolution, as a way
* of configuring their execution for the template being processed.
*
*
* Note that template resolution attributes are considered a part of the identifier of a template,
* so they will be used as a part of the keys for cached templates. It is therefore
* required that template attribute maps contain values with valid {@link #equals(Object)}
* and {@link #hashCode()} implementations. Therefore, using simple (and fast)
* Map<String,String> maps is the recommended option.
*
*
* This constructor will set no template selectors or forced template mode.
*
*
* @param template the template (usually the template name), required.
* @param templateResolutionAttributes the template resolution attributes, can be null.
*/
public TemplateSpec(final String template, final Map templateResolutionAttributes) {
this(template, null, null, null, templateResolutionAttributes);
}
/**
*
* Build a new object of this class, specifying a template mode that should be forced for template
* execution, ignoring the mode resolved by template resolvers.
*
*
* The template usually represents the template name, but can be the entire template
* contents if the template is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* Template selectors allow the possibility to process only a part of the specified template, expressing
* this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for
* markup template modes (HTML, XML). For more info on template selectors
* syntax, have a look at AttoParser's markup selectors
* documentation.
*
*
* The template mode only needs to be specified in cases when we want to force a template
* mode to be used for a template, independently of the mode that is selected for it by the configured
* template resolvers.
*
*
* The template resolution attributes are meant to be passed to the template resolvers (see
* {@link org.thymeleaf.templateresolver.ITemplateResolver} during template resolution, as a way
* of configuring their execution for the template being processed.
*
*
* Note that template resolution attributes are considered a part of the identifier of a template,
* so they will be used as a part of the keys for cached templates. It is therefore
* required that template attribute maps contain values with valid {@link #equals(Object)}
* and {@link #hashCode()} implementations. Therefore, using simple (and fast)
* Map<String,String> maps is the recommended option.
*
*
* @param template the template (usually the template name), required.
* @param templateSelectors the template selectors to be applied on the template.
* @param templateMode the template mode to be forced, can be null.
* @param templateResolutionAttributes the template resolution attributes, can be null.
*/
public TemplateSpec(
final String template, final Set templateSelectors, final TemplateMode templateMode,
final Map templateResolutionAttributes) {
this(template, templateSelectors, templateMode, null, templateResolutionAttributes);
}
/**
*
* Build a new object of this class, specifying an output content type (MIME type). Most of the times this
* will force a template mode for template execution (e.g. text/html, application/javascript),
* but not always (e.g. text/event-stream).
*
*
* The template usually represents the template name, but can be the entire template
* contents if the template is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* Template selectors allow the possibility to process only a part of the specified template, expressing
* this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for
* markup template modes (HTML, XML). For more info on template selectors
* syntax, have a look at AttoParser's markup selectors
* documentation.
*
*
* The template resolution attributes are meant to be passed to the template resolvers (see
* {@link org.thymeleaf.templateresolver.ITemplateResolver} during template resolution, as a way
* of configuring their execution for the template being processed.
*
*
* Supported relations between template mode and output content type are:
*
*
* - HTML: text/html, application/xhtml+xml
* - XML: application/xml
* - JAVASCRIPT: application/javascript, application/x-javascript,
* application/ecmascript, text/javascript,
* text/ecmascript, application/json
* - CSS: text/css
* - TEXT: text/plain
*
*
* The text/event-stream content type will also be supported, but will have no effect in
* forcing a template mode. Instead, it will put the engine into Server-Sent Event (SSE) output mode.
*
*
* Note content type parameters will be ignored (only the mime type itself will be used).
*
*
* Note that template resolution attributes are considered a part of the identifier of a template,
* so they will be used as a part of the keys for cached templates. It is therefore
* required that template attribute maps contain values with valid {@link #equals(Object)}
* and {@link #hashCode()} implementations. Therefore, using simple (and fast)
* Map<String,String> maps is the recommended option.
*
*
* @param template the template (usually the template name), required.
* @param templateSelectors the template selectors to be applied on the template.
* @param outputContentType the expected output content type, can be null.
* @param templateResolutionAttributes the template resolution attributes, can be null.
*
* @since 3.0.6
*/
public TemplateSpec(
final String template, final Set templateSelectors, final String outputContentType,
final Map templateResolutionAttributes) {
this(template, templateSelectors, null, outputContentType, templateResolutionAttributes);
}
/**
*
* Build a new object of this class, specifying all its attributes.
*
*
* @param template the template (usually the template name), required.
* @param templateSelectors the template selectors to be applied on the template.
* @param templateMode the template mode to be forced, can be null.
* @param outputContentType the expected output content type, can be null.
* @param templateResolutionAttributes the template resolution attributes, can be null.
*
* @since 3.0.4
*/
TemplateSpec(
final String template, final Set templateSelectors,
final TemplateMode templateMode, final String outputContentType,
final Map templateResolutionAttributes) {
super();
Validate.notNull(template, "Template cannot be null");
Validate.isTrue(templateMode == null || outputContentType == null,
"If template mode or output content type are specified, the other one cannot");
// templateSelectors CAN be null
// templateMode CAN be null
// outputContentType CAN be null
// templateResolutionAttributes CAN be null
// ONLY one of templateMode or outputContentType can be not-null
this.template = template;
if (templateSelectors != null && !templateSelectors.isEmpty()) {
Validate.containsNoEmpties(
templateSelectors, "If specified, the Template Selector set cannot contain any nulls or empties");
if (templateSelectors.size() == 1) {
this.templateSelectors = Collections.singleton(templateSelectors.iterator().next());
} else {
// We will be using a TreeSet because we want the selectors to be ORDERED, so that comparison at the
// equals(...) method works alright
this.templateSelectors = Collections.unmodifiableSet(new TreeSet(templateSelectors));
}
} else {
this.templateSelectors = null;
}
this.templateResolutionAttributes =
(templateResolutionAttributes != null && !templateResolutionAttributes.isEmpty()?
Collections.unmodifiableMap(new HashMap(templateResolutionAttributes)) : null);
this.outputContentType = outputContentType;
final TemplateMode computedTemplateMode =
ContentTypeUtils.computeTemplateModeForContentType(this.outputContentType);
if (computedTemplateMode != null) {
this.templateMode = computedTemplateMode;
} else {
this.templateMode = templateMode;
}
this.outputSSE = ContentTypeUtils.isContentTypeSSE(this.outputContentType);
}
/**
*
* Returns the template (usually the template name).
*
*
* This template normally represents the template name, but can be the entire template
* contents if the template is meant to be specified as a String and resolved by a
* {@link org.thymeleaf.templateresolver.StringTemplateResolver}.
*
*
* @return the template. Cannot be null.
*/
public String getTemplate() {
return this.template;
}
/**
*
* Returns whether this spec has template selectors specified or not.
*
*
* @return true of there are template selectors, false if not.
*/
public boolean hasTemplateSelectors() {
// Checking for null is enough, as we have already processed this in the constructor
return this.templateSelectors != null;
}
/**
*
* Returns the template selectors, if there are any.
*
*
* Template selectors allow the possibility to process only a part of the specified template, expressing
* this selection in a syntax similar to jQuery, CSS or XPath selectors. Note this is only available for
* markup template modes (HTML, XML). For more info on template selectors
* syntax, have a look at AttoParser's markup selectors
* documentation.
*
*
* @return the template selectors, or null if there are none.
*/
public Set getTemplateSelectors() {
return this.templateSelectors;
}
/**
*
* Returns whether this spec has template mode specified or not.
*
*
* @return true of there is a template mode, false if not.
*/
public boolean hasTemplateMode() {
return this.templateMode != null;
}
/**
*
* Returns the template mode, if it has been specified.
*
*
* The template mode only needs to be specified in cases when we want to force a template
* mode to be used for a template, independently of the mode that is selected for it by the configured
* template resolvers.
*
*
* @return the template mode specified, or null if there isn't any.
*/
public TemplateMode getTemplateMode() {
return this.templateMode;
}
/**
*
* Returns whether this spec includes template resolution attributes or not.
*
*
* @return true of there are template resolution attributes, false if not.
*/
public boolean hasTemplateResolutionAttributes() {
// Checking for null is enough, as we have already processed this in the constructor
return this.templateResolutionAttributes != null;
}
/**
*
* Returns the template resolution attributes, if any have been specified.
*
*
* The template resolution attributes are meant to be passed to the template resolvers (see
* {@link org.thymeleaf.templateresolver.ITemplateResolver} during template resolution, as a way
* of configuring their execution for the template being processed.
*
*
* Note that template resolution attributes are considered a part of the identifier of a template,
* so they will be used as a part of the keys for cached templates. It is therefore
* required that template attribute maps contain values with valid {@link #equals(Object)}
* and {@link #hashCode()} implementations. Therefore, using simple (and fast)
* Map<String,String> maps is the recommended option.
*
*
* @return the template resolution attributes.
*/
public Map getTemplateResolutionAttributes() {
return this.templateResolutionAttributes;
}
/**
*
* Returns the output content type (MIME type). Most of the times this
* will force a template mode for template execution (e.g. text/html, application/javascript),
* but not always (e.g. text/event-stream).
*
*
* Supported relations between template mode and output content type are:
*
*
* - HTML: text/html, application/xhtml+xml
* - XML: application/xml
* - JAVASCRIPT: application/javascript, application/x-javascript,
* application/ecmascript, text/javascript,
* text/ecmascript, application/json
* - CSS: text/css
* - TEXT: text/plain
*
*
* The text/event-stream content type will also be supported, but will have no effect in
* forcing a template mode. Instead, it will put the engine into Server-Sent Event (SSE) output mode.
*
*
* Note content type parameters will be ignored (only the mime type itself will be used).
*
*
* @return the output content type, or null if none was specified.
*/
public String getOutputContentType() {
return this.outputContentType;
}
/**
*
* Returns whether output should be Server-Sent Events (SSE) or not.
*
*
* Server-Sent Events mode is enabled by setting the text/event-stream mime type
* as *output content type* constructor argument.
*
*
* @return true if output is supposed to be done via Server-Sent Events (SSE), false if not.
*
* @since 3.0.6
*/
public boolean isOutputSSE() {
return this.outputSSE;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof TemplateSpec)) {
return false;
}
final TemplateSpec that = (TemplateSpec) o;
if (!this.template.equals(that.template)) {
return false;
}
if (this.templateSelectors != null ? !this.templateSelectors.equals(that.templateSelectors) : that.templateSelectors != null) {
return false;
}
if (this.templateMode != that.templateMode) {
return false;
}
if (!this.outputContentType.equals(that.outputContentType)) {
return false;
}
// Note how it is important that template resolution attribute values correctly implement equals() and hashCode()
return !(this.templateResolutionAttributes != null ? !this.templateResolutionAttributes.equals(that.templateResolutionAttributes) : that.templateResolutionAttributes != null);
}
@Override
public int hashCode() {
int result = this.template.hashCode();
result = 31 * result + (this.templateSelectors != null ? this.templateSelectors.hashCode() : 0);
result = 31 * result + (this.templateMode != null ? this.templateMode.hashCode() : 0);
result = 31 * result + (this.outputContentType != null ? this.outputContentType.hashCode() : 0);
result = 31 * result + (this.templateResolutionAttributes != null ? this.templateResolutionAttributes.hashCode() : 0);
return result;
}
@Override
public String toString() {
final StringBuilder strBuilder = new StringBuilder();
strBuilder.append(LoggingUtils.loggifyTemplateName(this.template));
if (this.templateSelectors != null) {
strBuilder.append("::");
strBuilder.append(this.templateSelectors);
}
if (this.templateMode != null) {
strBuilder.append(" @");
strBuilder.append(this.templateMode);
}
if (this.templateResolutionAttributes != null) {
strBuilder.append(" (");
strBuilder.append(this.templateResolutionAttributes);
strBuilder.append(")");
}
if (this.outputContentType != null) {
strBuilder.append(" [");
strBuilder.append(this.outputContentType);
strBuilder.append("]");
}
return strBuilder.toString();
}
}