use of org.thymeleaf.processor.templateboundaries.ITemplateBoundariesProcessor in project thymeleaf-tests by thymeleaf.
the class DialectProcessWrappingTest method testDialectWrapping.
@Test
public void testDialectWrapping() throws Exception {
final Dialect01 dialect01 = new Dialect01();
final TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setDialect(dialect01);
final IEngineConfiguration config = templateEngine.getConfiguration();
final List<IElementProcessor> elementProcessors = new ArrayList<IElementProcessor>(config.getElementProcessors(TemplateMode.HTML));
final List<ICDATASectionProcessor> cdataSectionProcessors = new ArrayList<ICDATASectionProcessor>(config.getCDATASectionProcessors(TemplateMode.HTML));
final List<ICommentProcessor> commentProcessors = new ArrayList<ICommentProcessor>(config.getCommentProcessors(TemplateMode.HTML));
final List<IDocTypeProcessor> docTypeProcessors = new ArrayList<IDocTypeProcessor>(config.getDocTypeProcessors(TemplateMode.HTML));
final List<IProcessingInstructionProcessor> processingInstructionProcessors = new ArrayList<IProcessingInstructionProcessor>(config.getProcessingInstructionProcessors(TemplateMode.HTML));
final List<ITemplateBoundariesProcessor> templateBoundariesProcessors = new ArrayList<ITemplateBoundariesProcessor>(config.getTemplateBoundariesProcessors(TemplateMode.HTML));
final List<ITextProcessor> textProcessors = new ArrayList<ITextProcessor>(config.getTextProcessors(TemplateMode.HTML));
final List<IXMLDeclarationProcessor> xmlDeclarationProcessors = new ArrayList<IXMLDeclarationProcessor>(config.getXMLDeclarationProcessors(TemplateMode.HTML));
Assert.assertEquals(2, elementProcessors.size());
Assert.assertEquals(1, cdataSectionProcessors.size());
Assert.assertEquals(1, commentProcessors.size());
Assert.assertEquals(1, docTypeProcessors.size());
Assert.assertEquals(1, processingInstructionProcessors.size());
Assert.assertEquals(1, templateBoundariesProcessors.size());
Assert.assertEquals(1, textProcessors.size());
Assert.assertEquals(1, xmlDeclarationProcessors.size());
// We will use the class names because the classes are package-protected
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$ElementModelProcessorWrapper", elementProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper", elementProcessors.get(1).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$CDATASectionProcessorWrapper", cdataSectionProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$CommentProcessorWrapper", commentProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$DocTypeProcessorWrapper", docTypeProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$ProcessingInstructionProcessorWrapper", processingInstructionProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$TemplateBoundariesProcessorWrapper", templateBoundariesProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$TextProcessorWrapper", textProcessors.get(0).getClass().getName());
Assert.assertEquals("org.thymeleaf.util.ProcessorConfigurationUtils$XMLDeclarationProcessorWrapper", xmlDeclarationProcessors.get(0).getClass().getName());
Assert.assertEquals(100, elementProcessors.get(0).getPrecedence());
Assert.assertEquals(110, elementProcessors.get(1).getPrecedence());
Assert.assertEquals(100, cdataSectionProcessors.get(0).getPrecedence());
Assert.assertEquals(100, commentProcessors.get(0).getPrecedence());
Assert.assertEquals(100, docTypeProcessors.get(0).getPrecedence());
Assert.assertEquals(100, processingInstructionProcessors.get(0).getPrecedence());
Assert.assertEquals(100, templateBoundariesProcessors.get(0).getPrecedence());
Assert.assertEquals(100, textProcessors.get(0).getPrecedence());
Assert.assertEquals(100, xmlDeclarationProcessors.get(0).getPrecedence());
}
use of org.thymeleaf.processor.templateboundaries.ITemplateBoundariesProcessor in project thymeleaf by thymeleaf.
the class DialectSetConfiguration method build.
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) {
// cannot be null -- ConfigurationDialect checks this
final IDialect dialect = dialectConfiguration.getDialect();
/*
* 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);
}
Aggregations