org.thymeleaf.Configuration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.everit.osgi.bundles.org.thymeleaf.thymeleaf Show documentation
Show all versions of org.everit.osgi.bundles.org.thymeleaf.thymeleaf Show documentation
XML/XHTML/HTML5 template engine for Java
The newest version!
/*
* =============================================================================
*
* Copyright (c) 2011-2013, 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.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.thymeleaf.cache.ICacheManager;
import org.thymeleaf.dialect.IDialect;
import org.thymeleaf.doctype.DocTypeIdentifier;
import org.thymeleaf.doctype.resolution.IDocTypeResolutionEntry;
import org.thymeleaf.doctype.translation.IDocTypeTranslation;
import org.thymeleaf.dom.Element;
import org.thymeleaf.dom.NestableAttributeHolderNode;
import org.thymeleaf.dom.Node;
import org.thymeleaf.exceptions.AlreadyInitializedException;
import org.thymeleaf.exceptions.ConfigurationException;
import org.thymeleaf.exceptions.NotInitializedException;
import org.thymeleaf.messageresolver.IMessageResolver;
import org.thymeleaf.processor.ProcessorAndContext;
import org.thymeleaf.standard.StandardDialect;
import org.thymeleaf.templatemode.ITemplateModeHandler;
import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.util.Validate;
/**
*
* General configuration class, containing all the configuration items
* for a {@link TemplateEngine}, including all the info for every configured
* {@link IDialect}.
*
*
* Except for testing purposes, there is no reason why a user might need to use this
* class directly.
*
*
* @author Daniel Fernández
*
* @since 1.0
*
*/
public final class Configuration {
/**
* @deprecated Deprecated in 2.1.0. Create a new instance of the StandardDialect using its constructors instead.
* Will be removed in 3.0
*/
@Deprecated
public static final IDialect STANDARD_THYMELEAF_DIALECT = new StandardDialect();
private static final TemplateResolverComparator TEMPLATE_RESOLVER_COMPARATOR = new TemplateResolverComparator();
private static final MessageResolverComparator MESSAGE_RESOLVER_COMPARATOR = new MessageResolverComparator();
private Set dialectConfigurations = null;
private Map dialectsByPrefix = null;
private Set dialectSet = null;
private Set templateResolvers = new LinkedHashSet(3);
private Set messageResolvers = new LinkedHashSet(3);
private Set templateModeHandlers = new LinkedHashSet(8);
private ICacheManager cacheManager = null;
private Map> mergedSpecificProcessorsByElementName;
private Map> mergedSpecificProcessorsByAttributeName;
private Map, Set> mergedNonSpecificProcessorsByNodeClass;
private Map mergedExecutionAttributes = null;
private Set mergedDocTypeResolutionEntries = null;
private Set mergedDocTypeTranslations = null;
private final Map templateModeHandlersByName = new HashMap(8,1.0f);
private Set defaultMessageResolvers = null;
private Set defaultTemplateModeHandlers = null;
private volatile boolean initialized;
public Configuration() {
super();
final StandardDialect standardDialect = new StandardDialect();
this.dialectConfigurations = new LinkedHashSet(4);
this.dialectConfigurations.add(
new DialectConfiguration(standardDialect.getPrefix(), standardDialect));
this.initialized = false;
}
private boolean isInitialized() {
return this.initialized;
}
private void checkNotInitialized() {
if (isInitialized()) {
throw new AlreadyInitializedException(
"Cannot modify template engine configuration when it has already been initialized");
}
}
private void checkInitialized() {
if (!isInitialized()) {
throw new NotInitializedException("Configuration has not been initialized");
}
}
public synchronized void initialize() {
if (!isInitialized()) {
/*
* Checking dialects exist
*/
if (this.dialectConfigurations == null) {
throw new ConfigurationException("Cannot initialize: a dialect has not been set");
}
/*
* Initialize dialect configurations
*/
for (final DialectConfiguration dialectConfiguration : this.dialectConfigurations) {
dialectConfiguration.initialize();
}
/*
* Initialize "dialects by prefix" map and the "dialect set"
*/
this.dialectsByPrefix = new LinkedHashMap(4,1.0f);
for (final DialectConfiguration dialectConfiguration : this.dialectConfigurations) {
this.dialectsByPrefix.put(dialectConfiguration.getPrefix(), dialectConfiguration.getDialect());
}
this.dialectsByPrefix = Collections.unmodifiableMap(this.dialectsByPrefix);
this.dialectSet = Collections.unmodifiableSet(new LinkedHashSet(this.dialectsByPrefix.values()));
/*
* Merge dialects
*/
final MergedDialectArtifacts mergedDialectArtifacts = mergeDialects(this.dialectConfigurations);
this.mergedSpecificProcessorsByElementName =
Collections.unmodifiableMap(mergedDialectArtifacts.getSpecificProcessorsByElementName());
this.mergedSpecificProcessorsByAttributeName =
Collections.unmodifiableMap(mergedDialectArtifacts.getSpecificProcessorsByAttributeName());
this.mergedNonSpecificProcessorsByNodeClass =
Collections.unmodifiableMap(mergedDialectArtifacts.getMergedNonSpecificProcessorsByNodeClass());
this.mergedExecutionAttributes =
Collections.unmodifiableMap(mergedDialectArtifacts.getExecutionAttributes());
this.mergedDocTypeResolutionEntries =
Collections.unmodifiableSet(mergedDialectArtifacts.getDocTypeResolutionEntries());
this.mergedDocTypeTranslations =
Collections.unmodifiableSet(mergedDialectArtifacts.getDocTypeTranslations());
/*
* Checking template resolvers
*/
if (this.templateResolvers == null || this.templateResolvers.size() <= 0) {
throw new ConfigurationException("Cannot initialize: no template resolvers have been set");
}
final List templateResolversList =
new ArrayList(this.templateResolvers);
for (final ITemplateResolver templateResolver : templateResolversList) {
templateResolver.initialize();
}
Collections.sort(templateResolversList, TEMPLATE_RESOLVER_COMPARATOR);
this.templateResolvers = new LinkedHashSet(templateResolversList);
/*
* Checking message resolvers
*/
if (this.messageResolvers == null) {
throw new ConfigurationException("Cannot initialize: message resolvers set is null");
}
if (this.messageResolvers.size() == 0) {
// No message resolvers have been set, so default initialization will be performed
if (this.defaultMessageResolvers == null || this.defaultMessageResolvers.size() == 0) {
throw new ConfigurationException(
"Cannot initialize: no message resolvers have been set and " +
"no default message resolvers have been set either.");
}
this.messageResolvers = this.defaultMessageResolvers;
}
for (final IMessageResolver messageResolver : this.messageResolvers) {
messageResolver.initialize();
}
final List messageResolversList =
new ArrayList(this.messageResolvers);
Collections.sort(messageResolversList, MESSAGE_RESOLVER_COMPARATOR);
this.messageResolvers = new LinkedHashSet(messageResolversList);
/*
* Checking template mode handlers
*/
if (this.templateModeHandlers == null) {
throw new ConfigurationException("Cannot initialize: template mode handlers set is null");
}
if (this.templateModeHandlers.size() == 0) {
// No message resolvers have been set, so default initialization will be performed
if (this.defaultTemplateModeHandlers == null || this.defaultTemplateModeHandlers.size() == 0) {
throw new ConfigurationException(
"Cannot initialize: no template mode handlers have been set and " +
"no default template mode handlers have been set either.");
}
this.templateModeHandlers = this.defaultTemplateModeHandlers;
}
for (final ITemplateModeHandler handler : this.templateModeHandlers) {
if (this.templateModeHandlersByName.containsKey(handler.getTemplateModeName())) {
throw new ConfigurationException(
"More than one handler configured for template mode \"" + handler.getTemplateModeName() + "\"");
}
if (handler.getTemplateParser() == null) {
throw new ConfigurationException(
"Null parser returned by handler for template mode \"" + handler.getTemplateModeName() + "\"");
}
this.templateModeHandlersByName.put(handler.getTemplateModeName(), handler);
}
/*
* Mark as initialized
*/
this.initialized = true;
}
}
void printConfiguration() {
ConfigurationPrinterHelper.printConfiguration(
this.dialectConfigurations, this.templateResolvers, this.messageResolvers,
this.cacheManager, this.templateModeHandlers);
}
public ICacheManager getCacheManager() {
return this.cacheManager;
}
public void setCacheManager(final ICacheManager cacheManager) {
// Can be set to null (= no caches)
checkNotInitialized();
this.cacheManager = cacheManager;
}
public Set getDialectSet() {
if (!isInitialized()) {
// If we haven't initialized yet, compute
return Collections.unmodifiableSet(new LinkedHashSet(getDialects().values()));
}
return this.dialectSet;
}
public Map getDialects() {
if (!isInitialized()) {
// If we haven't initialized yet, compute
final Map dialects = new LinkedHashMap(4, 1.0f);
for (final DialectConfiguration dialectConfiguration : this.dialectConfigurations) {
dialects.put(dialectConfiguration.getPrefix(), dialectConfiguration.getDialect());
}
return Collections.unmodifiableMap(dialects);
}
return this.dialectsByPrefix;
}
public void setDialects(final Map dialects) {
checkNotInitialized();
Validate.notNull(dialects, "Dialect set cannot be null");
Validate.isTrue(dialects.size() > 0, "Dialect set cannot be empty");
this.dialectConfigurations.clear();
for (final Map.Entry dialectEntry : dialects.entrySet()) {
this.dialectConfigurations.add(new DialectConfiguration(dialectEntry.getKey(), dialectEntry.getValue()));
}
}
public void setDialect(final IDialect dialect) {
checkNotInitialized();
Validate.notNull(dialect, "Dialect set cannot be null");
this.dialectConfigurations.clear();
this.dialectConfigurations.add(new DialectConfiguration(dialect.getPrefix(), dialect));
}
public void addDialect(final String prefix, final IDialect dialect) {
checkNotInitialized();
Validate.notNull(dialect, "Dialect set cannot be null");
this.dialectConfigurations.add(new DialectConfiguration(prefix, dialect));
}
public void clearDialects() {
checkNotInitialized();
this.dialectConfigurations.clear();
}
public Set getTemplateResolvers() {
return Collections.unmodifiableSet(this.templateResolvers);
}
public void setTemplateResolvers(final Set extends ITemplateResolver> templateResolvers) {
checkNotInitialized();
Validate.notNull(templateResolvers, "Template Resolver set cannot be null");
Validate.isTrue(templateResolvers.size() > 0, "Template Resolver set cannot be empty");
Validate.containsNoNulls(templateResolvers, "Template Resolver set cannot contain any nulls");
this.templateResolvers = new LinkedHashSet(templateResolvers);
}
public void addTemplateResolver(final ITemplateResolver templateResolver) {
checkNotInitialized();
Validate.notNull(templateResolver, "Template Resolver cannot be null");
this.templateResolvers.add(templateResolver);
}
public void setTemplateResolver(final ITemplateResolver templateResolver) {
checkNotInitialized();
Validate.notNull(templateResolver, "Template Resolver cannot be null");
this.templateResolvers = Collections.singleton(templateResolver);
}
public Set getMessageResolvers() {
return Collections.unmodifiableSet(this.messageResolvers);
}
public void setMessageResolvers(final Set extends IMessageResolver> messageResolvers) {
checkNotInitialized();
Validate.notNull(messageResolvers, "Message Resolver set cannot be null");
Validate.isTrue(messageResolvers.size() > 0, "Message Resolver set cannot be empty");
Validate.containsNoNulls(messageResolvers, "Message Resolver set cannot contain any nulls");
this.messageResolvers = new LinkedHashSet(messageResolvers);
}
public void addMessageResolver(final IMessageResolver messageResolver) {
checkNotInitialized();
Validate.notNull(messageResolver, "Message Resolver cannot be null");
this.messageResolvers.add(messageResolver);
}
public void setMessageResolver(final IMessageResolver messageResolver) {
checkNotInitialized();
Validate.notNull(messageResolver, "Message Resolver cannot be null");
this.messageResolvers = Collections.singleton(messageResolver);
}
public void setDefaultMessageResolvers(final Set extends IMessageResolver> defaultMessageResolvers) {
checkNotInitialized();
Validate.notNull(defaultMessageResolvers, "Default Message Resolver set cannot be null");
Validate.isTrue(defaultMessageResolvers.size() > 0, "Default Message Resolver set cannot be empty");
Validate.containsNoNulls(defaultMessageResolvers, "Default Message Resolver set cannot contain any nulls");
this.defaultMessageResolvers = new LinkedHashSet(defaultMessageResolvers);
}
public Set getTemplateModeHandlers() {
return Collections.unmodifiableSet(this.templateModeHandlers);
}
public ITemplateModeHandler getTemplateModeHandler(final String templateMode) {
return this.templateModeHandlersByName.get(templateMode);
}
public void setTemplateModeHandlers(final Set extends ITemplateModeHandler> templateModeHandlers) {
checkNotInitialized();
Validate.notNull(templateModeHandlers, "Template Mode Handler set cannot be null");
Validate.isTrue(templateModeHandlers.size() > 0, "Template Mode Handler set cannot be empty");
Validate.containsNoNulls(templateModeHandlers, "Template Mode Handler set cannot contain any nulls");
this.templateModeHandlers = new LinkedHashSet(templateModeHandlers);
}
public void addTemplateModeHandler(final ITemplateModeHandler templateModeHandler) {
checkNotInitialized();
Validate.notNull(templateModeHandler, "Template Mode Handler cannot be null");
this.templateModeHandlers.add(templateModeHandler);
}
public void setDefaultTemplateModeHandlers(final Set extends ITemplateModeHandler> defaultTemplateModeHandlers) {
checkNotInitialized();
Validate.notNull(defaultTemplateModeHandlers, "Default Template Mode Handler set cannot be null");
Validate.isTrue(defaultTemplateModeHandlers.size() > 0, "Default Template Mode Handler set cannot be empty");
Validate.containsNoNulls(defaultTemplateModeHandlers, "Default Template Mode Handler set cannot contain any nulls");
this.defaultTemplateModeHandlers = new LinkedHashSet(defaultTemplateModeHandlers);
}
public Set getDocTypeTranslations() {
checkInitialized();
return this.mergedDocTypeTranslations;
}
public IDocTypeTranslation getDocTypeTranslationBySource(final String publicID, final String systemID) {
checkInitialized();
for (final IDocTypeTranslation translation : this.mergedDocTypeTranslations) {
if (translation.getSourcePublicID().matches(publicID) && translation.getSourceSystemID().matches(systemID)) {
return translation;
}
}
return null;
}
public Set getDocTypeResolutionEntries() {
checkInitialized();
return this.mergedDocTypeResolutionEntries;
}
/**
*
* Computes all the processors that should be applied to a specific {@link Node}.
*
*
* Results are returned ordered by precedence.
*
*
* @param node the node to compute
* @return an ArrayList with the list of processors, as {@link ProcessorAndContext} objects.
*/
public ArrayList computeProcessorsForNode(final Node node) {
if (node instanceof NestableAttributeHolderNode) {
final ArrayList processors = new ArrayList(2);
final NestableAttributeHolderNode nestableNode = (NestableAttributeHolderNode) node;
if (node instanceof Element) {
final Element element = (Element) nestableNode;
final Set processorsForElementName =
this.mergedSpecificProcessorsByElementName.get(element.getNormalizedName());
if (processorsForElementName != null) {
for (final ProcessorAndContext processorAndContext : processorsForElementName) {
if (processorAndContext.matches(node)) {
processors.add(processorAndContext);
}
}
}
}
final String[] normalizedAttributeNames = nestableNode.unsafeGetAttributeNormalizedNames();
final int normalizedAttributesLen = nestableNode.numAttributes();
for (int i = 0; i < normalizedAttributesLen; i++) {
final String normalizedAttributeName = normalizedAttributeNames[i];
final Set processorsForAttributeName =
this.mergedSpecificProcessorsByAttributeName.get(normalizedAttributeName);
if (processorsForAttributeName != null) {
for (final ProcessorAndContext processorAndContext : processorsForAttributeName) {
if (processorAndContext.matches(node)) {
processors.add(processorAndContext);
}
}
}
}
final Set applicableNonSpecificProcessors =
getApplicableNonSpecificProcessorsToNodeClass(NestableAttributeHolderNode.class);
if (applicableNonSpecificProcessors != null) {
for (final ProcessorAndContext processorAndContext : applicableNonSpecificProcessors) {
if (processorAndContext.matches(node)) {
processors.add(processorAndContext);
}
}
}
if (processors.size() > 1) {
// Order (usually by precedence)
Collections.sort(processors);
}
return processors;
}
//
// NODE IS NOT AN ELEMENT...
//
final Set applicableNonSpecificProcessors =
getApplicableNonSpecificProcessorsToNodeClass(node.getClass());
if (applicableNonSpecificProcessors != null) {
final ArrayList processors = new ArrayList(2);
for (final ProcessorAndContext processorAndContext : applicableNonSpecificProcessors) {
if (processorAndContext.matches(node)) {
processors.add(processorAndContext);
}
}
// Order (usually by precedence)
Collections.sort(processors);
return processors;
}
// No processors to be returned
return null;
}
public Map getExecutionAttributes() {
checkInitialized();
return this.mergedExecutionAttributes;
}
public Set getAllPrefixes() {
checkInitialized();
return this.dialectsByPrefix.keySet();
}
public boolean isPrefixManaged(final String prefix) {
return this.dialectsByPrefix.containsKey(prefix);
}
private Set getApplicableNonSpecificProcessorsToNodeClass(final Class extends Node> nodeClass) {
Set result = null;
for (final Map.Entry, Set> entry : this.mergedNonSpecificProcessorsByNodeClass.entrySet()) {
final Class extends Node> entryNodeClass = entry.getKey();
if (entryNodeClass.isAssignableFrom(nodeClass)) {
if (result == null) {
result = new HashSet(2);
}
result.addAll(entry.getValue());
}
}
return result;
}
private static MergedDialectArtifacts mergeDialects(final Set dialectConfigurations) {
if (dialectConfigurations == null || dialectConfigurations.isEmpty()) {
throw new ConfigurationException("No dialect has been specified");
}
final Map> specificProcessorsByElementName = new HashMap>(20);
final Map> specificProcessorsByAttributeName = new HashMap>(20);
final Map, Set> nonSpecificProcessorsByNodeClass = new HashMap, Set>(20);
final Map executionAttributes = new HashMap(20);
final Set docTypeResolutionEntries = new HashSet(20);
final Set docTypeTranslations = new HashSet(20);
if (dialectConfigurations.size() == 1) {
// No conflicts possible!
final DialectConfiguration dialectConfiguration = dialectConfigurations.iterator().next();
final IDialect dialect = dialectConfiguration.getDialect();
specificProcessorsByElementName.putAll(dialectConfiguration.unsafeGetSpecificProcessorsByElementName());
specificProcessorsByAttributeName.putAll(dialectConfiguration.unsafeGetSpecificProcessorsByAttributeName());
nonSpecificProcessorsByNodeClass.putAll(dialectConfiguration.unsafeGetNonSpecificProcessorsByNodeClass());
executionAttributes.putAll(dialectConfiguration.getExecutionAttributes());
docTypeResolutionEntries.addAll(dialect.getDocTypeResolutionEntries());
docTypeTranslations.addAll(dialect.getDocTypeTranslations());
return new MergedDialectArtifacts(
specificProcessorsByElementName, specificProcessorsByAttributeName, nonSpecificProcessorsByNodeClass,
executionAttributes, dialect.getDocTypeResolutionEntries(), dialect.getDocTypeTranslations());
}
/*
* THERE ARE MORE THAN ONE DIALECT: MERGE THEM
*/
final Set> mergedDialectClasses = new HashSet>(5,1.0f);
for (final DialectConfiguration dialectConfiguration : dialectConfigurations) {
final IDialect dialect = dialectConfiguration.getDialect();
/*
* Check the dialect is not being repeated
*/
if (mergedDialectClasses.contains(dialect.getClass())) {
throw new ConfigurationException(
"Dialect is declared twice: " + dialect.getClass().getName());
}
/*
* Aggregate all the processors assigned to a specific element name
*/
specificProcessorsByElementName.putAll(dialectConfiguration.unsafeGetSpecificProcessorsByElementName());
/*
* Aggregate all the processors assigned to a specific attribute name
*/
specificProcessorsByAttributeName.putAll(dialectConfiguration.unsafeGetSpecificProcessorsByAttributeName());
/*
* Aggregate all the processors not assigned to a specific attribute or element name
*/
nonSpecificProcessorsByNodeClass.putAll(dialectConfiguration.unsafeGetNonSpecificProcessorsByNodeClass());
/*
* Merge execution attributes
*/
executionAttributes.putAll(dialectConfiguration.getExecutionAttributes());
/*
* Check that two dialects do not specify conflicting DOCTYPE resolution entries
* for the same PUBLIC and SYSTEM IDs.
*/
final Set dialectDocTypeResolutionEntries =
dialect.getDocTypeResolutionEntries();
for (final IDocTypeResolutionEntry dialectDocTypeResolutionEntry : dialectDocTypeResolutionEntries) {
boolean addDialectDocTypeResolutionEntry = true;
final DocTypeIdentifier dialectDocTypeResolutionEntryPublicID = dialectDocTypeResolutionEntry.getPublicID();
final DocTypeIdentifier dialectDocTypeResolutionEntrySystemID = dialectDocTypeResolutionEntry.getSystemID();
for (final IDocTypeResolutionEntry docTypeResolutionEntry : docTypeResolutionEntries) {
final DocTypeIdentifier docTypeResolutionEntryPublicID = docTypeResolutionEntry.getPublicID();
final DocTypeIdentifier docTypeResolutionEntrySystemID = docTypeResolutionEntry.getSystemID();
final boolean publicIDMatches;
if (dialectDocTypeResolutionEntryPublicID == null) {
publicIDMatches = (docTypeResolutionEntryPublicID == null);
} else {
publicIDMatches = (docTypeResolutionEntryPublicID != null && docTypeResolutionEntryPublicID.equals(dialectDocTypeResolutionEntryPublicID));
}
final boolean systemIDMatches;
if (dialectDocTypeResolutionEntrySystemID == null) {
systemIDMatches = (docTypeResolutionEntrySystemID == null);
} else {
systemIDMatches = (docTypeResolutionEntrySystemID != null && docTypeResolutionEntrySystemID.equals(dialectDocTypeResolutionEntrySystemID));
}
if (publicIDMatches && systemIDMatches) {
if (!dialectDocTypeResolutionEntry.equals(docTypeResolutionEntry)) {
throw new ConfigurationException(
"Cannot initialize: two dialects provide different (non-equal) " +
"DOCTYPE resolution entries for PUBLICID \"" + docTypeResolutionEntryPublicID +
"\" and SYSTEMID \"" + docTypeResolutionEntrySystemID + "\"");
}
// No need to repeat an entry (even if it is a Set!)
addDialectDocTypeResolutionEntry = false;
}
}
if (addDialectDocTypeResolutionEntry) {
docTypeResolutionEntries.add(dialectDocTypeResolutionEntry);
}
}
/*
* Check that two dialects do not specify conflicting DOCTYPE translations
* for the same PUBLIC and SYSTEM IDs.
*/
final Set dialectDocTypeTranslations = dialect.getDocTypeTranslations();
for (final IDocTypeTranslation dialectDocTypeTranslation : dialectDocTypeTranslations) {
boolean addDialectDocTypeTranslation = true;
final DocTypeIdentifier dialectDocTypeTranslationSourcePublicID = dialectDocTypeTranslation.getSourcePublicID();
final DocTypeIdentifier dialectDocTypeTranslationSourceSystemID = dialectDocTypeTranslation.getSourceSystemID();
final DocTypeIdentifier dialectDocTypeTranslationTargetPublicID = dialectDocTypeTranslation.getTargetPublicID();
final DocTypeIdentifier dialectDocTypeTranslationTargetSystemID = dialectDocTypeTranslation.getTargetSystemID();
for (final IDocTypeTranslation docTypeTranslation : docTypeTranslations) {
final DocTypeIdentifier docTypeTranslationSourcePublicID = docTypeTranslation.getSourcePublicID();
final DocTypeIdentifier docTypeTranslationSourceSystemID = docTypeTranslation.getSourceSystemID();
final DocTypeIdentifier docTypeTranslationTargetPublicID = docTypeTranslation.getTargetPublicID();
final DocTypeIdentifier docTypeTranslationTargetSystemID = docTypeTranslation.getTargetSystemID();
boolean sourcePublicIDMatches = false;
boolean sourceSystemIDMatches = false;
if (dialectDocTypeTranslationSourcePublicID == null) {
sourcePublicIDMatches = (docTypeTranslationSourcePublicID == null);
} else {
sourcePublicIDMatches = (docTypeTranslationSourcePublicID != null && docTypeTranslationSourcePublicID.equals(dialectDocTypeTranslationSourcePublicID));
}
if (dialectDocTypeTranslationSourceSystemID == null) {
sourceSystemIDMatches = (docTypeTranslationSourceSystemID == null);
} else {
sourceSystemIDMatches = (docTypeTranslationSourceSystemID != null && docTypeTranslationSourceSystemID.equals(dialectDocTypeTranslationSourceSystemID));
}
if (sourcePublicIDMatches && sourceSystemIDMatches) {
final boolean targetPublicIDMatches;
if (dialectDocTypeTranslationTargetPublicID == null) {
targetPublicIDMatches = (docTypeTranslationTargetPublicID == null);
} else {
targetPublicIDMatches = (docTypeTranslationTargetPublicID != null && docTypeTranslationTargetPublicID.equals(dialectDocTypeTranslationTargetPublicID));
}
final boolean targetSystemIDMatches;
if (dialectDocTypeTranslationTargetSystemID == null) {
targetSystemIDMatches = (docTypeTranslationTargetSystemID == null);
} else {
targetSystemIDMatches = (docTypeTranslationTargetSystemID != null && docTypeTranslationTargetSystemID.equals(dialectDocTypeTranslationTargetSystemID));
}
if (!targetPublicIDMatches || !targetSystemIDMatches) {
throw new ConfigurationException(
"Cannot initialize: two dialects provide different (non-equal) " +
"DOCTYPE translations for PUBLICID \"" + docTypeTranslationSourcePublicID +
"\" and SYSTEMID \"" + docTypeTranslationSourceSystemID + "\"");
}
// No need to repeat a translation (even if it is a Set!)
addDialectDocTypeTranslation = false;
}
}
if (addDialectDocTypeTranslation) {
docTypeTranslations.add(dialectDocTypeTranslation);
}
}
mergedDialectClasses.add(dialect.getClass());
}
return new MergedDialectArtifacts(
specificProcessorsByElementName, specificProcessorsByAttributeName, nonSpecificProcessorsByNodeClass,
executionAttributes, docTypeResolutionEntries, docTypeTranslations);
}
private static final class MergedDialectArtifacts {
private final Map> specificProcessorsByElementName;
private final Map> specificProcessorsByAttributeName;
private final Map, Set> nonSpecificProcessorsByNodeClass;
private final Map executionAttributes;
private final Set docTypeResolutionEntries;
private final Set docTypeTranslations;
MergedDialectArtifacts(
final Map> specificProcessorsByElementName,
final Map> specificProcessorsByAttributeName,
final Map,Set> nonSpecificProcessorsByNodeClass,
final Map executionAttributes,
final Set docTypeResolutionEntries,
final Set docTypeTranslations) {
super();
this.specificProcessorsByElementName = specificProcessorsByElementName;
this.specificProcessorsByAttributeName = specificProcessorsByAttributeName;
this.nonSpecificProcessorsByNodeClass = nonSpecificProcessorsByNodeClass;
this.executionAttributes = executionAttributes;
this.docTypeResolutionEntries = docTypeResolutionEntries;
this.docTypeTranslations = docTypeTranslations;
}
public Map> getSpecificProcessorsByElementName() {
return this.specificProcessorsByElementName;
}
public Map> getSpecificProcessorsByAttributeName() {
return this.specificProcessorsByAttributeName;
}
public Map, Set> getMergedNonSpecificProcessorsByNodeClass() {
return this.nonSpecificProcessorsByNodeClass;
}
public Map getExecutionAttributes() {
return this.executionAttributes;
}
public Set getDocTypeResolutionEntries() {
return this.docTypeResolutionEntries;
}
public Set getDocTypeTranslations() {
return this.docTypeTranslations;
}
}
private static class TemplateResolverComparator implements Comparator, Serializable {
private static final long serialVersionUID = -4959505530260386645L;
TemplateResolverComparator() {
super();
}
public int compare(final ITemplateResolver o1, final ITemplateResolver o2) {
if (o1.getOrder() == null) {
return -1;
}
if (o2.getOrder() == null) {
return 1;
}
return o1.getOrder().compareTo(o2.getOrder());
}
}
private static class MessageResolverComparator implements Comparator, Serializable {
private static final long serialVersionUID = 4700426328261944024L;
MessageResolverComparator() {
super();
}
public int compare(final IMessageResolver o1, final IMessageResolver o2) {
if (o1.getOrder() == null) {
return -1;
}
if (o2.getOrder() == null) {
return 1;
}
return o1.getOrder().compareTo(o2.getOrder());
}
}
}