/* * ============================================================================= * * 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.util.ArrayList; import java.util.Collections; import java.util.EnumMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.thymeleaf.context.IExpressionContext; import org.thymeleaf.dialect.IDialect; import org.thymeleaf.dialect.IExecutionAttributeDialect; import org.thymeleaf.dialect.IExpressionObjectDialect; import org.thymeleaf.dialect.IPostProcessorDialect; import org.thymeleaf.dialect.IPreProcessorDialect; import org.thymeleaf.dialect.IProcessorDialect; import org.thymeleaf.engine.AttributeDefinitions; import org.thymeleaf.engine.ElementDefinitions; import org.thymeleaf.engine.IAttributeDefinitionsAware; import org.thymeleaf.engine.IElementDefinitionsAware; import org.thymeleaf.engine.ITemplateHandler; import org.thymeleaf.exceptions.ConfigurationException; import org.thymeleaf.expression.IExpressionObjectFactory; import org.thymeleaf.postprocessor.IPostProcessor; import org.thymeleaf.preprocessor.IPreProcessor; import org.thymeleaf.processor.IProcessor; import org.thymeleaf.processor.cdatasection.ICDATASectionProcessor; import org.thymeleaf.processor.comment.ICommentProcessor; import org.thymeleaf.processor.doctype.IDocTypeProcessor; import org.thymeleaf.processor.element.IElementProcessor; import org.thymeleaf.processor.processinginstruction.IProcessingInstructionProcessor; import org.thymeleaf.processor.templateboundaries.ITemplateBoundariesProcessor; import org.thymeleaf.processor.text.ITextProcessor; import org.thymeleaf.processor.xmldeclaration.IXMLDeclarationProcessor; import org.thymeleaf.standard.StandardDialect; import org.thymeleaf.templatemode.TemplateMode; import org.thymeleaf.util.ProcessorComparators; import org.thymeleaf.util.ProcessorConfigurationUtils; import org.thymeleaf.util.Validate; /** * * @author Daniel Fernández * @since 3.0.0 * */ final class DialectSetConfiguration { private final Set<DialectConfiguration> dialectConfigurations; private final Set<IDialect> dialects; private final boolean standardDialectPresent; private final String standardDialectPrefix; private final Map<String,Object> executionAttributes; private final AggregateExpressionObjectFactory expressionObjectFactory; private final ElementDefinitions elementDefinitions; private final AttributeDefinitions attributeDefinitions; private final EnumMap<TemplateMode,Set<ITemplateBoundariesProcessor>> templateBoundariesProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<ICDATASectionProcessor>> cdataSectionProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<ICommentProcessor>> commentProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<IDocTypeProcessor>> docTypeProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<IElementProcessor>> elementProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<IProcessingInstructionProcessor>> processingInstructionProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<ITextProcessor>> textProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<IXMLDeclarationProcessor>> xmlDeclarationProcessorsByTemplateMode; private final EnumMap<TemplateMode,Set<IPreProcessor>> preProcessors; private final EnumMap<TemplateMode,Set<IPostProcessor>> postProcessors; public static DialectSetConfiguration build(final Set<DialectConfiguration> dialectConfigurations) { Validate.notNull(dialectConfigurations, "Dialect configuration set cannot be null"); // This set will contain all the dialects - without any additional configuration information final Set<IDialect> dialects = new LinkedHashSet<IDialect>(dialectConfigurations.size()); // If we find a standard dialect among the configured ones (Standard or SpringStandard), we will report its prefix boolean standardDialectPresent = false; String standardDialectPrefix = null; // This map will be used for merging the execution attributes of all the dialects final Map<String, Object> executionAttributes = new LinkedHashMap<String, Object>(10, 1.0f); // This will aggregate all the expression object factories provided by the different dialects final AggregateExpressionObjectFactory aggregateExpressionObjectFactory = new AggregateExpressionObjectFactory(); // EnumMaps for each type of processor (depending on the structures that they can be applied to) final EnumMap<TemplateMode, List<ITemplateBoundariesProcessor>> templateBoundariesProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<ITemplateBoundariesProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<ICDATASectionProcessor>> cdataSectionProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<ICDATASectionProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<ICommentProcessor>> commentProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<ICommentProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<IDocTypeProcessor>> docTypeProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<IDocTypeProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<IElementProcessor>> elementProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<IElementProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<IProcessingInstructionProcessor>> processingInstructionProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<IProcessingInstructionProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<ITextProcessor>> textProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<ITextProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<IXMLDeclarationProcessor>> xmlDeclarationProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<IXMLDeclarationProcessor>>(TemplateMode.class); // Lists for merging all pre and postprocessors from all dialects final EnumMap<TemplateMode, List<IPreProcessor>> preProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<IPreProcessor>>(TemplateMode.class); final EnumMap<TemplateMode, List<IPostProcessor>> postProcessorListsByTemplateMode = new EnumMap<TemplateMode, List<IPostProcessor>>(TemplateMode.class); /* * ITERATE ALL DIALECTS, processing each one according to its features */ for (final DialectConfiguration dialectConfiguration : dialectConfigurations) { final IDialect dialect = dialectConfiguration.getDialect(); // cannot be null -- ConfigurationDialect checks this /* * STEP ONE for each dialect: process, initialize and merge processors */ if (dialect instanceof IProcessorDialect) { final IProcessorDialect processorDialect = (IProcessorDialect)dialect; // Might be null if the dialect has been specified to use no prefix (or that is the default of such dialect) final String dialectPrefix = (dialectConfiguration.isPrefixSpecified()? dialectConfiguration.getPrefix() : processorDialect.getPrefix()); if (dialect instanceof StandardDialect) { standardDialectPresent = true; standardDialectPrefix = dialectPrefix; } final Set<IProcessor> dialectProcessors = processorDialect.getProcessors(dialectPrefix); if (dialectProcessors == null) { throw new ConfigurationException("Dialect should not return null processor set: " + dialect.getClass().getName()); } for (final IProcessor dialectProcessor : dialectProcessors) { if (dialectProcessor == null) { throw new ConfigurationException("Dialect should not return null processor in processor set: " + dialect.getClass().getName()); } // Obtain and check template mode final TemplateMode templateMode = dialectProcessor.getTemplateMode(); if (templateMode == null) { throw new ConfigurationException("Template mode cannot be null (processor: " + dialectProcessor.getClass().getName() + ")"); } if (dialectProcessor instanceof IElementProcessor) { // can be either a tag processor or a node one List<IElementProcessor> processorsForTemplateMode = elementProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<IElementProcessor>(5); elementProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((IElementProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof ITemplateBoundariesProcessor) { List<ITemplateBoundariesProcessor> processorsForTemplateMode = templateBoundariesProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<ITemplateBoundariesProcessor>(5); templateBoundariesProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((ITemplateBoundariesProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof ICDATASectionProcessor) { List<ICDATASectionProcessor> processorsForTemplateMode = cdataSectionProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<ICDATASectionProcessor>(5); cdataSectionProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((ICDATASectionProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof ICommentProcessor) { List<ICommentProcessor> processorsForTemplateMode = commentProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<ICommentProcessor>(5); commentProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((ICommentProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof IDocTypeProcessor) { List<IDocTypeProcessor> processorsForTemplateMode = docTypeProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<IDocTypeProcessor>(5); docTypeProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((IDocTypeProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof IProcessingInstructionProcessor) { List<IProcessingInstructionProcessor> processorsForTemplateMode = processingInstructionProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<IProcessingInstructionProcessor>(5); processingInstructionProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((IProcessingInstructionProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof ITextProcessor) { List<ITextProcessor> processorsForTemplateMode = textProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<ITextProcessor>(5); textProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((ITextProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } else if (dialectProcessor instanceof IXMLDeclarationProcessor) { List<IXMLDeclarationProcessor> processorsForTemplateMode = xmlDeclarationProcessorListsByTemplateMode.get(templateMode); if (processorsForTemplateMode == null) { processorsForTemplateMode = new ArrayList<IXMLDeclarationProcessor>(5); xmlDeclarationProcessorListsByTemplateMode.put(templateMode, processorsForTemplateMode); } processorsForTemplateMode.add(ProcessorConfigurationUtils.wrap((IXMLDeclarationProcessor)dialectProcessor, processorDialect)); Collections.sort(processorsForTemplateMode, ProcessorComparators.PROCESSOR_COMPARATOR); } } } /* * STEP TWO for each dialect: merge execution attributes */ if (dialect instanceof IExecutionAttributeDialect) { final Map<String, Object> dialectExecutionAttributes = ((IExecutionAttributeDialect) dialect).getExecutionAttributes(); if (dialectExecutionAttributes != null) { for (final Map.Entry<String, Object> entry : dialectExecutionAttributes.entrySet()) { final String executionAttributeName = entry.getKey(); if (executionAttributes.containsKey(executionAttributeName)) { throw new ConfigurationException( "Conflicting execution attribute. Two or more dialects specify an execution " + "attribute with the same name \"" + executionAttributeName + "\"."); } executionAttributes.put(entry.getKey(), entry.getValue()); } } } /* * STEP THREE for each dialect: aggregate all the expression object factories */ if (dialect instanceof IExpressionObjectDialect) { final IExpressionObjectFactory factory = ((IExpressionObjectDialect) dialect).getExpressionObjectFactory(); if (factory != null) { aggregateExpressionObjectFactory.add(factory); } } /* * STEP FOUR for each dialect: aggregate pre-processors (and check the correctness of the list) */ if (dialect instanceof IPreProcessorDialect) { final Set<IPreProcessor> dialectPreProcessors = ((IPreProcessorDialect)dialect).getPreProcessors(); if (dialectPreProcessors != null) { for (final IPreProcessor preProcessor : dialectPreProcessors) { if (preProcessor == null) { throw new ConfigurationException( "Pre-Processor list for dialect " + dialect.getClass().getName() + " includes a " + "null entry, which is forbidden."); } // Obtain and check template mode final TemplateMode templateMode = preProcessor.getTemplateMode(); if (templateMode == null) { throw new ConfigurationException( "Template mode cannot be null (pre-processor: " + preProcessor.getClass().getName() + ", dialect" + dialect.getClass().getName() + ")"); } // Check the handler class: should extend ITemplateHandler and have an empty constructor final Class<?> handlerClass = preProcessor.getHandlerClass(); if (handlerClass == null) { throw new ConfigurationException( "Pre-Processor " + preProcessor.getClass().getName() + " for dialect " + preProcessor.getClass().getName() + " returns a null handler class, which is forbidden."); } if (!ITemplateHandler.class.isAssignableFrom(handlerClass)) { throw new ConfigurationException( "Handler class " + handlerClass.getName() + " specified for " + "pre-processor " + preProcessor.getClass().getName() + " in dialect " + dialect.getClass().getName() + " does not implement required " + "interface " + ITemplateHandler.class.getName()); } try { // Check the empty constructor is present -- we will need to use it for creating new instances handlerClass.getConstructor(new Class[0]); } catch (final NoSuchMethodException e) { throw new ConfigurationException( "Pre-Processor class " + handlerClass.getName() + " specified for " + "pre-processor " + preProcessor.getClass().getName() + " in dialect " + dialect.getClass().getName() + " does not implement required " + "zero-argument constructor.", e); } // Add the pre-processor to its corresponding map and sort List<IPreProcessor> preProcessorsForTemplateMode = preProcessorListsByTemplateMode.get(templateMode); if (preProcessorsForTemplateMode == null) { preProcessorsForTemplateMode = new ArrayList<IPreProcessor>(5); preProcessorListsByTemplateMode.put(templateMode, preProcessorsForTemplateMode); } preProcessorsForTemplateMode.add(preProcessor); Collections.sort(preProcessorsForTemplateMode, ProcessorComparators.PRE_PROCESSOR_COMPARATOR); } } } /* * STEP FIVE for each dialect: aggregate post-processors (and check the correctness of the list) */ if (dialect instanceof IPostProcessorDialect) { final Set<IPostProcessor> dialectPostProcessors = ((IPostProcessorDialect)dialect).getPostProcessors(); if (dialectPostProcessors != null) { for (final IPostProcessor postProcessor : dialectPostProcessors) { if (postProcessor == null) { throw new ConfigurationException( "Post-Processor list for dialect " + dialect.getClass().getName() + " includes a " + "null entry, which is forbidden."); } // Obtain and check template mode final TemplateMode templateMode = postProcessor.getTemplateMode(); if (templateMode == null) { throw new ConfigurationException( "Template mode cannot be null (post-processor: " + postProcessor.getClass().getName() + ", dialect" + dialect.getClass().getName() + ")"); } // Check the handler class: should extend ITemplateHandler and have an empty constructor final Class<?> handlerClass = postProcessor.getHandlerClass(); if (handlerClass == null) { throw new ConfigurationException( "Post-Processor " + postProcessor.getClass().getName() + " for dialect " + postProcessor.getClass().getName() + " returns a null handler class, which is forbidden."); } if (!ITemplateHandler.class.isAssignableFrom(handlerClass)) { throw new ConfigurationException( "Handler class " + handlerClass.getName() + " specified for " + "post-processor " + postProcessor.getClass().getName() + " in dialect " + dialect.getClass().getName() + " does not implement required " + "interface " + ITemplateHandler.class.getName()); } try { // Check the empty constructor is present -- we will need to use it for creating new instances handlerClass.getConstructor(new Class[0]); } catch (final NoSuchMethodException e) { throw new ConfigurationException( "Post-Processor class " + handlerClass.getName() + " specified for " + "post-processor " + postProcessor.getClass().getName() + " in dialect " + dialect.getClass().getName() + " does not implement required " + "zero-argument constructor.", e); } // Add the pre-processor to its corresponding map and sort List<IPostProcessor> postProcessorsForTemplateMode = postProcessorListsByTemplateMode.get(templateMode); if (postProcessorsForTemplateMode == null) { postProcessorsForTemplateMode = new ArrayList<IPostProcessor>(5); postProcessorListsByTemplateMode.put(templateMode, postProcessorsForTemplateMode); } postProcessorsForTemplateMode.add(postProcessor); Collections.sort(postProcessorsForTemplateMode, ProcessorComparators.POST_PROCESSOR_COMPARATOR); } } } /* * LAST STEP for each dialect: add it to the dialects set */ dialects.add(dialect); } // Time to turn the list-based structures into sets -- we needed the lists because we needed a way to order them using Collections.sort() final EnumMap<TemplateMode, Set<ITemplateBoundariesProcessor>> templateBoundariesProcessorsByTemplateMode = listMapToSetMap(templateBoundariesProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<ICDATASectionProcessor>> cdataSectionProcessorsByTemplateMode = listMapToSetMap(cdataSectionProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<ICommentProcessor>> commentProcessorsByTemplateMode = listMapToSetMap(commentProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<IDocTypeProcessor>> docTypeProcessorsByTemplateMode = listMapToSetMap(docTypeProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<IElementProcessor>> elementProcessorsByTemplateMode = listMapToSetMap(elementProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<IProcessingInstructionProcessor>> processingInstructionProcessorsByTemplateMode = listMapToSetMap(processingInstructionProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<ITextProcessor>> textProcessorsByTemplateMode = listMapToSetMap(textProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<IXMLDeclarationProcessor>> xmlDeclarationProcessorsByTemplateMode = listMapToSetMap(xmlDeclarationProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<IPreProcessor>> preProcessorsByTemplateMode = listMapToSetMap(preProcessorListsByTemplateMode); final EnumMap<TemplateMode, Set<IPostProcessor>> postProcessorsByTemplateMode = listMapToSetMap(postProcessorListsByTemplateMode); // Initialize the ElementDefinitions and AttributeDefinitions structures -- they need the element processors so that these // are directly applied to the element/attribute definitions and therefore per element/attribute matching is not required // during template processing. final ElementDefinitions elementDefinitions = new ElementDefinitions(elementProcessorsByTemplateMode); final AttributeDefinitions attributeDefinitions = new AttributeDefinitions(elementProcessorsByTemplateMode); // Traverse the sets of processors in order to set the AttributeDefinitions and/or ElementDefinitions objects // to those that need them in order to initialize and cache attribute/element definition-related structures initializeDefinitionsForProcessors(templateBoundariesProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(cdataSectionProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(commentProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(docTypeProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(elementProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(processingInstructionProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(textProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForProcessors(xmlDeclarationProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForPreProcessors(preProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); initializeDefinitionsForPostProcessors(postProcessorsByTemplateMode, elementDefinitions, attributeDefinitions); return new DialectSetConfiguration( new LinkedHashSet<DialectConfiguration>(dialectConfigurations), dialects, standardDialectPresent, standardDialectPrefix, executionAttributes, aggregateExpressionObjectFactory, elementDefinitions, attributeDefinitions, templateBoundariesProcessorsByTemplateMode, cdataSectionProcessorsByTemplateMode, commentProcessorsByTemplateMode, docTypeProcessorsByTemplateMode, elementProcessorsByTemplateMode, processingInstructionProcessorsByTemplateMode, textProcessorsByTemplateMode, xmlDeclarationProcessorsByTemplateMode, preProcessorsByTemplateMode, postProcessorsByTemplateMode); } private static <T> EnumMap<TemplateMode, Set<T>> listMapToSetMap(final EnumMap<TemplateMode, List<T>> map) { final EnumMap<TemplateMode, Set<T>> newMap = new EnumMap<TemplateMode, Set<T>>(TemplateMode.class); for (final Map.Entry<TemplateMode, List<T>> entry : map.entrySet()) { newMap.put(entry.getKey(), new LinkedHashSet<T>(entry.getValue())); } return newMap; } private static void initializeDefinitionsForProcessors( final EnumMap<TemplateMode, ? extends Set<? extends IProcessor>> processorsByTemplateMode, final ElementDefinitions elementDefinitions, final AttributeDefinitions attributeDefinitions) { for (final Map.Entry<TemplateMode, ? extends Set<? extends IProcessor>> entry : processorsByTemplateMode.entrySet()) { final Set<? extends IProcessor> processors = entry.getValue(); for (final IProcessor processor : processors) { if (processor instanceof IElementDefinitionsAware) { ((IElementDefinitionsAware) processor).setElementDefinitions(elementDefinitions); } if (processor instanceof IAttributeDefinitionsAware) { ((IAttributeDefinitionsAware) processor).setAttributeDefinitions(attributeDefinitions); } } } } private static void initializeDefinitionsForPreProcessors( final EnumMap<TemplateMode, ? extends Set<IPreProcessor>> preProcessorsByTemplateMode, final ElementDefinitions elementDefinitions, final AttributeDefinitions attributeDefinitions) { for (final Map.Entry<TemplateMode, ? extends Set<IPreProcessor>> entry : preProcessorsByTemplateMode.entrySet()) { final Set<IPreProcessor> preProcessors = entry.getValue(); for (final IPreProcessor preProcessor : preProcessors) { if (preProcessor instanceof IElementDefinitionsAware) { ((IElementDefinitionsAware) preProcessor).setElementDefinitions(elementDefinitions); } if (preProcessor instanceof IAttributeDefinitionsAware) { ((IAttributeDefinitionsAware) preProcessor).setAttributeDefinitions(attributeDefinitions); } } } } private static void initializeDefinitionsForPostProcessors( final EnumMap<TemplateMode, ? extends Set<IPostProcessor>> postProcessorsByTemplateMode, final ElementDefinitions elementDefinitions, final AttributeDefinitions attributeDefinitions) { for (final Map.Entry<TemplateMode, ? extends Set<IPostProcessor>> entry : postProcessorsByTemplateMode.entrySet()) { final Set<IPostProcessor> postProcessors = entry.getValue(); for (final IPostProcessor postProcessor : postProcessors) { if (postProcessor instanceof IElementDefinitionsAware) { ((IElementDefinitionsAware) postProcessor).setElementDefinitions(elementDefinitions); } if (postProcessor instanceof IAttributeDefinitionsAware) { ((IAttributeDefinitionsAware) postProcessor).setAttributeDefinitions(attributeDefinitions); } } } } private DialectSetConfiguration( final Set<DialectConfiguration> dialectConfigurations, final Set<IDialect> dialects, final boolean standardDialectPresent, final String standardDialectPrefix, final Map<String, Object> executionAttributes, final AggregateExpressionObjectFactory expressionObjectFactory, final ElementDefinitions elementDefinitions, final AttributeDefinitions attributeDefinitions, final EnumMap<TemplateMode, Set<ITemplateBoundariesProcessor>> templateBoundariesProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<ICDATASectionProcessor>> cdataSectionProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<ICommentProcessor>> commentProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<IDocTypeProcessor>> docTypeProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<IElementProcessor>> elementProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<IProcessingInstructionProcessor>> processingInstructionProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<ITextProcessor>> textProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<IXMLDeclarationProcessor>> xmlDeclarationProcessorsByTemplateMode, final EnumMap<TemplateMode, Set<IPreProcessor>> preProcessors, final EnumMap<TemplateMode, Set<IPostProcessor>> postProcessors) { super(); this.dialectConfigurations = Collections.unmodifiableSet(dialectConfigurations); this.dialects = Collections.unmodifiableSet(dialects); this.standardDialectPresent = standardDialectPresent; this.standardDialectPrefix = standardDialectPrefix; this.executionAttributes = Collections.unmodifiableMap(executionAttributes); this.expressionObjectFactory = expressionObjectFactory; this.elementDefinitions = elementDefinitions; this.attributeDefinitions = attributeDefinitions; this.templateBoundariesProcessorsByTemplateMode = templateBoundariesProcessorsByTemplateMode; this.cdataSectionProcessorsByTemplateMode = cdataSectionProcessorsByTemplateMode; this.commentProcessorsByTemplateMode = commentProcessorsByTemplateMode; this.docTypeProcessorsByTemplateMode = docTypeProcessorsByTemplateMode; this.elementProcessorsByTemplateMode = elementProcessorsByTemplateMode; this.processingInstructionProcessorsByTemplateMode = processingInstructionProcessorsByTemplateMode; this.textProcessorsByTemplateMode = textProcessorsByTemplateMode; this.xmlDeclarationProcessorsByTemplateMode = xmlDeclarationProcessorsByTemplateMode; this.preProcessors = preProcessors; this.postProcessors = postProcessors; } public Set<DialectConfiguration> getDialectConfigurations() { return this.dialectConfigurations; } public Set<IDialect> getDialects() { return this.dialects; } public boolean isStandardDialectPresent() { return this.standardDialectPresent; } public String getStandardDialectPrefix() { return this.standardDialectPrefix; } public Map<String,Object> getExecutionAttributes() { return this.executionAttributes; } public Object getExecutionAttribute(final String executionAttributeName) { return this.executionAttributes.get(executionAttributeName); } public boolean hasExecutionAttribute(final String executionAttributeName) { return this.executionAttributes.containsKey(executionAttributeName); } public ElementDefinitions getElementDefinitions() { return this.elementDefinitions; } public AttributeDefinitions getAttributeDefinitions() { return this.attributeDefinitions; } public Set<ITemplateBoundariesProcessor> getTemplateBoundariesProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<ITemplateBoundariesProcessor> processors = this.templateBoundariesProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<ICDATASectionProcessor> getCDATASectionProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<ICDATASectionProcessor> processors = this.cdataSectionProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<ICommentProcessor> getCommentProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<ICommentProcessor> processors = this.commentProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<IDocTypeProcessor> getDocTypeProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<IDocTypeProcessor> processors = this.docTypeProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<IElementProcessor> getElementProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<IElementProcessor> processors = this.elementProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<IProcessingInstructionProcessor> getProcessingInstructionProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<IProcessingInstructionProcessor> processors = this.processingInstructionProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<ITextProcessor> getTextProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<ITextProcessor> processors = this.textProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<IXMLDeclarationProcessor> getXMLDeclarationProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<IXMLDeclarationProcessor> processors = this.xmlDeclarationProcessorsByTemplateMode.get(templateMode); if (processors == null) { return Collections.EMPTY_SET; } return processors; } public Set<IPreProcessor> getPreProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<IPreProcessor> preProcessors = this.preProcessors.get(templateMode); if (preProcessors == null) { return Collections.EMPTY_SET; } return preProcessors; } public Set<IPostProcessor> getPostProcessors(final TemplateMode templateMode) { Validate.notNull(templateMode, "Template mode cannot be null"); final Set<IPostProcessor> postProcessors = this.postProcessors.get(templateMode); if (postProcessors == null) { return Collections.EMPTY_SET; } return postProcessors; } public IExpressionObjectFactory getExpressionObjectFactory() { return this.expressionObjectFactory; } /* * This class serves the purpose of aggregating all the registered expression object factories so that * obtaining all the objects from an IProcessingContext implementation is easier. */ static class AggregateExpressionObjectFactory implements IExpressionObjectFactory { /* * We will try to optimize a bit the fact that most times only one dialect will provide an * IExpressionObjects implementation, so there should be no need to create a collection */ private IExpressionObjectFactory firstExpressionObjectFactory = null; private List<IExpressionObjectFactory> expressionObjectFactoryList = null; AggregateExpressionObjectFactory() { super(); } void add(final IExpressionObjectFactory expressionObjectFactory) { if (this.firstExpressionObjectFactory == null && this.expressionObjectFactoryList == null) { this.firstExpressionObjectFactory = expressionObjectFactory; return; } else if (this.expressionObjectFactoryList == null) { this.expressionObjectFactoryList = new ArrayList<IExpressionObjectFactory>(2); this.expressionObjectFactoryList.add(this.firstExpressionObjectFactory); this.firstExpressionObjectFactory = null; } this.expressionObjectFactoryList.add(expressionObjectFactory); } public Set<String> getAllExpressionObjectNames() { if (this.firstExpressionObjectFactory != null) { return this.firstExpressionObjectFactory.getAllExpressionObjectNames(); } if (this.expressionObjectFactoryList == null) { return null; } final Set<String> expressionObjectNames = new LinkedHashSet<String>(30); int n = this.expressionObjectFactoryList.size(); while (n-- != 0) { expressionObjectNames.addAll(this.expressionObjectFactoryList.get(n).getAllExpressionObjectNames()); } return expressionObjectNames; } public Object buildObject(final IExpressionContext context, final String expressionObjectName) { if (this.firstExpressionObjectFactory != null) { return this.firstExpressionObjectFactory.buildObject(context, expressionObjectName); } if (this.expressionObjectFactoryList == null) { return null; } int n = this.expressionObjectFactoryList.size(); while (n-- != 0) { if (this.expressionObjectFactoryList.get(n).getAllExpressionObjectNames().contains(expressionObjectName)) { return this.expressionObjectFactoryList.get(n).buildObject(context, expressionObjectName); } } return null; } public boolean isCacheable(final String expressionObjectName) { if (this.firstExpressionObjectFactory != null) { return this.firstExpressionObjectFactory.isCacheable(expressionObjectName); } if (this.expressionObjectFactoryList == null) { return false; } int n = this.expressionObjectFactoryList.size(); while (n-- != 0) { if (this.expressionObjectFactoryList.get(n).getAllExpressionObjectNames().contains(expressionObjectName)) { return this.expressionObjectFactoryList.get(n).isCacheable(expressionObjectName); } } return false; } } }