Search in sources :

Example 1 with IElementProcessor

use of org.thymeleaf.processor.element.IElementProcessor in project thymeleaf-tests by thymeleaf.

the class DialectOrderingTest method testDialectOrder.

@Test
public void testDialectOrder() throws Exception {
    final Dialect01 dialect01 = new Dialect01();
    final Dialect02 dialect02 = new Dialect02();
    final Dialect03 dialect03 = new Dialect03();
    final Dialect04 dialect04 = new Dialect04();
    final Set<IElementProcessor> dialect01Processors = combineDialects(dialect01);
    final Set<IElementProcessor> dialect02Processors = combineDialects(dialect02);
    final Set<IElementProcessor> dialect03Processors = combineDialects(dialect03);
    final Set<IElementProcessor> dialect04Processors = combineDialects(dialect04);
    List<IProcessor> d01ProcList = new ArrayList<IProcessor>(dialect01Processors);
    List<IProcessor> d02ProcList = new ArrayList<IProcessor>(dialect02Processors);
    List<IProcessor> d03ProcList = new ArrayList<IProcessor>(dialect03Processors);
    List<IProcessor> d04ProcList = new ArrayList<IProcessor>(dialect04Processors);
    Assert.assertEquals(2, d01ProcList.size());
    Assert.assertEquals(2, d02ProcList.size());
    Assert.assertEquals(2, d03ProcList.size());
    Assert.assertEquals(3, d04ProcList.size());
    // 110 - 1000
    Assert.assertEquals(P1Processor.class.getSimpleName(), unwrappedClassName(d01ProcList.get(0)));
    // 110 - 1100
    Assert.assertEquals(Div1Processor.class.getSimpleName(), unwrappedClassName(d01ProcList.get(1)));
    // 100 -  900
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d02ProcList.get(0)));
    // 100 - 1100
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d02ProcList.get(1)));
    // 90 -  800
    Assert.assertEquals(P3Processor.class.getSimpleName(), unwrappedClassName(d03ProcList.get(0)));
    // 90 -  900
    Assert.assertEquals(Span3Processor.class.getSimpleName(), unwrappedClassName(d03ProcList.get(1)));
    // 100 -  700
    Assert.assertEquals(Span4Processor.class.getSimpleName(), unwrappedClassName(d04ProcList.get(0)));
    // 100 - 1000
    Assert.assertEquals(Div4Processor.class.getSimpleName(), unwrappedClassName(d04ProcList.get(1)));
    // 100 - 1200
    Assert.assertEquals(P4Processor.class.getSimpleName(), unwrappedClassName(d04ProcList.get(2)));
    List<IElementProcessor> d0102ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect01, dialect02));
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d0102ProcList.get(0)));
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d0102ProcList.get(1)));
    Assert.assertEquals(P1Processor.class.getSimpleName(), unwrappedClassName(d0102ProcList.get(2)));
    Assert.assertEquals(Div1Processor.class.getSimpleName(), unwrappedClassName(d0102ProcList.get(3)));
    List<IElementProcessor> d0103ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect01, dialect03));
    Assert.assertEquals(P3Processor.class.getSimpleName(), unwrappedClassName(d0103ProcList.get(0)));
    Assert.assertEquals(Span3Processor.class.getSimpleName(), unwrappedClassName(d0103ProcList.get(1)));
    Assert.assertEquals(P1Processor.class.getSimpleName(), unwrappedClassName(d0103ProcList.get(2)));
    Assert.assertEquals(Div1Processor.class.getSimpleName(), unwrappedClassName(d0103ProcList.get(3)));
    List<IElementProcessor> d0203ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect02, dialect03));
    Assert.assertEquals(P3Processor.class.getSimpleName(), unwrappedClassName(d0203ProcList.get(0)));
    Assert.assertEquals(Span3Processor.class.getSimpleName(), unwrappedClassName(d0203ProcList.get(1)));
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d0203ProcList.get(2)));
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d0203ProcList.get(3)));
    List<IElementProcessor> d010204ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect01, dialect02, dialect04));
    Assert.assertEquals(Span4Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(0)));
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(1)));
    Assert.assertEquals(Div4Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(2)));
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(3)));
    Assert.assertEquals(P4Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(4)));
    Assert.assertEquals(P1Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(5)));
    Assert.assertEquals(Div1Processor.class.getSimpleName(), unwrappedClassName(d010204ProcList.get(6)));
    List<IElementProcessor> d010402ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect01, dialect04, dialect02));
    Assert.assertEquals(Span4Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(0)));
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(1)));
    Assert.assertEquals(Div4Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(2)));
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(3)));
    Assert.assertEquals(P4Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(4)));
    Assert.assertEquals(P1Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(5)));
    Assert.assertEquals(Div1Processor.class.getSimpleName(), unwrappedClassName(d010402ProcList.get(6)));
    List<IElementProcessor> d030402ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect03, dialect04, dialect02));
    Assert.assertEquals(P3Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(0)));
    Assert.assertEquals(Span3Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(1)));
    Assert.assertEquals(Span4Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(2)));
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(3)));
    Assert.assertEquals(Div4Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(4)));
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(5)));
    Assert.assertEquals(P4Processor.class.getSimpleName(), unwrappedClassName(d030402ProcList.get(6)));
    List<IElementProcessor> d020403ProcList = new ArrayList<IElementProcessor>(combineDialects(dialect02, dialect04, dialect03));
    Assert.assertEquals(P3Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(0)));
    Assert.assertEquals(Span3Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(1)));
    Assert.assertEquals(Span4Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(2)));
    Assert.assertEquals(Div2Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(3)));
    Assert.assertEquals(Div4Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(4)));
    Assert.assertEquals(P2Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(5)));
    Assert.assertEquals(P4Processor.class.getSimpleName(), unwrappedClassName(d020403ProcList.get(6)));
}
Also used : Dialect04(org.thymeleaf.dialect.dialectordering.Dialect04) Span4Processor(org.thymeleaf.dialect.dialectordering.Span4Processor) P3Processor(org.thymeleaf.dialect.dialectordering.P3Processor) Dialect02(org.thymeleaf.dialect.dialectordering.Dialect02) P1Processor(org.thymeleaf.dialect.dialectordering.P1Processor) Dialect03(org.thymeleaf.dialect.dialectordering.Dialect03) Div1Processor(org.thymeleaf.dialect.dialectordering.Div1Processor) ArrayList(java.util.ArrayList) Dialect01(org.thymeleaf.dialect.dialectordering.Dialect01) IProcessor(org.thymeleaf.processor.IProcessor) Span3Processor(org.thymeleaf.dialect.dialectordering.Span3Processor) Div2Processor(org.thymeleaf.dialect.dialectordering.Div2Processor) IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) P2Processor(org.thymeleaf.dialect.dialectordering.P2Processor) P4Processor(org.thymeleaf.dialect.dialectordering.P4Processor) Div4Processor(org.thymeleaf.dialect.dialectordering.Div4Processor) Test(org.junit.Test)

Example 2 with IElementProcessor

use of org.thymeleaf.processor.element.IElementProcessor in project thymeleaf by thymeleaf.

the class ProcessorTemplateHandler method handleStandaloneElement.

@Override
public void handleStandaloneElement(final IStandaloneElementTag istandaloneElementTag) {
    /*
         * If processing is stopped, we should queue this for later handling
         * In theory, given the origin of events (parser or cache) should get stopped immediately, this should
         * only happen if a pre-processor is producing additional events.
         */
    if (this.throttleEngine && this.flowController.stopProcessing) {
        queueEvent(istandaloneElementTag);
        return;
    }
    /*
         * CHECK WHETHER WE ARE GATHERING AN ELEMENT's MODEL
         */
    if (!this.modelController.shouldProcessStandaloneElement(istandaloneElementTag)) {
        return;
    }
    /*
         * CAST TO ENGINE-SPECIFIC IMPLEMENTATION, which will ease the handling of the structure during processing
         */
    StandaloneElementTag standaloneElementTag = StandaloneElementTag.asEngineStandaloneElementTag(istandaloneElementTag);
    /*
         * OBTAIN THE CURRENT SYNTHETIC MODEL (if any). This is needed in case this event was previously being handled,
         * then a gathering process started (as a consequence of the execution of one of its processors), and then
         * once the model was gathered the process started again by handling the first event, which was the one
         * suspended. By obtaining the current gathering model here we can reinitialize all the handling variables and
         * flags to their original state before being suspended.
         */
    final IGatheringModelProcessable currentGatheringModel = obtainCurrentGatheringModel();
    /*
         * If we are resuming an execution after suspending it, we want to retire the register of the element tag
         * that was added by the controller. The reason we want this is that the current tag was already registered
         * by the controller when the execution was suspended, and we don't want it duplicated (nor altered).
         */
    if (currentGatheringModel != null && this.engineContext != null) {
        this.engineContext.setElementTag(null);
    }
    /*
         * FAIL FAST in case this tag has no associated processors and we have no reason to pay attention to it
         * anyway (because of having been suspended).
         */
    if (currentGatheringModel == null && !standaloneElementTag.hasAssociatedProcessors()) {
        this.next.handleStandaloneElement(standaloneElementTag);
        if (!this.throttleEngine || !this.flowController.stopProcessing) {
            if (this.engineContext != null) {
                this.engineContext.decreaseLevel();
            }
        } else {
            queueProcessable(this.decreaseContextLevelProcessable);
        }
        return;
    }
    /*
         * DECLARE THE STATE VARS NEEDED FOR PROCESSOR EXECUTION. If we are executing the first event of a gathered
         * model, we will just re-initialize to the original variables, the ones we had before suspending.
         */
    final ProcessorExecutionVars vars = (currentGatheringModel == null ? new ProcessorExecutionVars() : currentGatheringModel.initializeProcessorExecutionVars());
    /*
         * GET THE STRUCTURE HANDLERS INTO LOCAL VARS
         */
    final ElementTagStructureHandler tagStructureHandler = this.elementTagStructureHandler;
    final ElementModelStructureHandler modelStructureHandler = this.elementModelStructureHandler;
    /*
         * EXECUTE PROCESSORS
         */
    IElementProcessor processor;
    while (!vars.discardEvent && (processor = vars.processorIterator.next(standaloneElementTag)) != null) {
        tagStructureHandler.reset();
        modelStructureHandler.reset();
        if (processor instanceof IElementTagProcessor) {
            final IElementTagProcessor elementProcessor = ((IElementTagProcessor) processor);
            elementProcessor.process(this.context, standaloneElementTag, tagStructureHandler);
            // Apply any context modifications made by the processor (local vars, inlining, etc.)
            tagStructureHandler.applyContextModifications(this.engineContext);
            // Apply any modifications to the tag itself: new/removed/replace attributes, etc. Note this
            // creates a new tag object because tag objects are immutable.
            standaloneElementTag = tagStructureHandler.applyAttributes(this.attributeDefinitions, standaloneElementTag);
            if (tagStructureHandler.iterateElement) {
                // Initialize a gathering model
                this.modelController.startGatheringIteratedModel(standaloneElementTag, vars, tagStructureHandler.iterVariableName, tagStructureHandler.iterStatusVariableName, tagStructureHandler.iteratedObject);
                // Obtain the gathered model (this is a standalone tag, so no additional events needed in iteration)
                final IGatheringModelProcessable gatheredModel = this.modelController.getGatheredModel();
                this.modelController.resetGathering();
                // Process the gathering model, or queue for throttled execution
                if (!this.throttleEngine) {
                    gatheredModel.process();
                } else {
                    queueProcessable(gatheredModel);
                }
                // Complete exit of the handler method: no more processing to do from here
                return;
            } else if (tagStructureHandler.setBodyText) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // Prepare the text node that will be added to the queue (which will be suspended)
                final Text text = new Text(tagStructureHandler.setBodyTextValue);
                vars.modelAfter.add(text);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.setBodyTextProcessable;
                // Initialize the gathered model object (open+close equivalent to this standalone tag)
                final GatheringModelProcessable equivalentSyntheticModel = this.modelController.createStandaloneEquivalentModel(standaloneElementTag, vars);
                // Fire the now-equivalent events. Note the handleOpenElement event will take care of the suspended queue
                if (!this.throttleEngine) {
                    equivalentSyntheticModel.process();
                } else {
                    queueProcessable(equivalentSyntheticModel);
                }
                // Complete exit of the handler method: no more processing to do from here
                return;
            } else if (tagStructureHandler.setBodyModel) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // Prepare the queue (that we will suspend)
                vars.modelAfter.addModel(tagStructureHandler.setBodyModelValue);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.setBodyModelProcessable;
                // Initialize the gathered model object (open+close equivalent to this standalone tag)
                final GatheringModelProcessable equivalentSyntheticModel = this.modelController.createStandaloneEquivalentModel(standaloneElementTag, vars);
                // Fire the now-equivalent events. Note the handleOpenElement event will take care of the suspended queue
                if (!this.throttleEngine) {
                    equivalentSyntheticModel.process();
                } else {
                    queueProcessable(equivalentSyntheticModel);
                }
                // Complete exit of the handler method: no more processing to do from here
                return;
            } else if (tagStructureHandler.insertBeforeModel) {
                // Reset BEFORE model, we need it clean
                vars.modelBefore = resetModel(vars.modelBefore, true);
                // Add model to be passed to this.next BEFORE delegating the event. Note this cannot be processable.
                vars.modelBefore.addModel(tagStructureHandler.insertBeforeModelValue);
            } else if (tagStructureHandler.insertImmediatelyAfterModel) {
                // will not be resetting it because we will be inserting our model at the very beginning of it.
                if (vars.modelAfter == null) {
                    vars.modelAfter = resetModel(vars.modelAfter, true);
                }
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.insertImmediatelyAfterModelProcessable;
                // Insert the new model
                vars.modelAfter.insertModel(0, tagStructureHandler.insertImmediatelyAfterModelValue);
            } else if (tagStructureHandler.replaceWithText) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.replaceWithTextProcessable;
                // Create the new replacement Text event and add it to the model
                vars.modelAfter.add(new Text(tagStructureHandler.replaceWithTextValue));
                // This tag, the standalone tag itself, will be replaced, so it has to be removed
                vars.discardEvent = true;
            } else if (tagStructureHandler.replaceWithModel) {
                // Reset model, we need it clean
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // If processable, events will be executed by the ProcessorTemplateHandler. If not, by this.next
                vars.modelAfterProcessable = tagStructureHandler.replaceWithModelProcessable;
                // Add the new replacement model
                vars.modelAfter.addModel(tagStructureHandler.replaceWithModelValue);
                // This tag, the standalone tag itself, will be replaced, so it has to be removed
                vars.discardEvent = true;
            } else if (tagStructureHandler.removeElement) {
                // Reset model, but only if it already exists
                vars.modelAfter = resetModel(vars.modelAfter, false);
                // We are removing the element (the standalone tag), so no further processing will be allowed
                vars.discardEvent = true;
            } else if (tagStructureHandler.removeTags) {
                // No modifications to the queue - it's just the tag that will be removed, not its possible contents
                vars.discardEvent = true;
            }
        // --------------
        // No way to process 'removeBody' or 'removeAllButFirstChild' on a standalone tag
        // --------------
        } else if (processor instanceof IElementModelProcessor) {
            if (!vars.processorIterator.lastWasRepeated()) {
                if ((vars.modelBefore != null && vars.modelBefore.size() > 0) || (vars.modelAfter != null && vars.modelAfter.size() > 0)) {
                    throw new TemplateProcessingException("Cannot execute model processor " + processor.getClass().getName() + " as the body " + "of the target element has already been modified by a previously executed processor " + "on the same tag. Model processors cannot execute on already-modified bodies as these " + "might contain unprocessable events (e.g. as a result of a 'th:text' or similar)", standaloneElementTag.getTemplateName(), standaloneElementTag.getLine(), standaloneElementTag.getCol());
                }
                // Set the processor to be executed again, because this time we will just set the "model gathering" mechanism
                vars.processorIterator.setLastToBeRepeated(standaloneElementTag);
                // Initialize the gathering model, and close it quickly because this is a standalone tag so there
                // is only one event to be gathered.
                this.modelController.startGatheringDelayedModel(standaloneElementTag, vars);
                final IGatheringModelProcessable newModel = this.modelController.getGatheredModel();
                this.modelController.resetGathering();
                // Process the new gathering model (no need to wait for a "close" event, as this is a standalone)
                if (!this.throttleEngine) {
                    newModel.process();
                } else {
                    queueProcessable(newModel);
                }
                // Nothing else to be done by this handler... let's just queue the rest of the events in this element
                return;
            }
            /*
                 * This is not the first time we try to execute this processor, which means the model gathering
                 * process has already taken place.
                 */
            // Create the actual Model instance (a clone) that will be passed to the processor to execute on
            final Model gatheredModel = currentGatheringModel.getInnerModel();
            final Model processedModel = new Model(gatheredModel);
            // Execute the processor on the just-created Model
            ((IElementModelProcessor) processor).process(this.context, processedModel, modelStructureHandler);
            // Apply any context modifications made by the processor (local vars, inlining, etc.)
            modelStructureHandler.applyContextModifications(this.engineContext);
            // Reset the skipbody flags so that the processed model can be executed in the same conditions as the original
            currentGatheringModel.resetGatheredSkipFlags();
            /*
                 * Before making any changes and queue the new model for execution, check that it actually is
                 * a "new" model (the processor might have been no-op on the tag and changes might have been
                 * only on the local variables, for example.)
                 */
            if (!gatheredModel.sameAs(processedModel)) {
                /*
                     * Now we will do the exact equivalent to what is performed for an Element Tag processor, when this
                     * returns a result of type "replaceWithModel".
                     */
                // Reset model
                vars.modelAfter = resetModel(vars.modelAfter, true);
                // Set the model to be executed, and set it to be processable (that is a MUST in this case)
                vars.modelAfter.addModel(processedModel);
                vars.modelAfterProcessable = true;
                // We will discard this event (the standalone one) because we are going to process the new, modified
                // model instead. Note we do not need to set the body to skip or anything because we know this is a
                // standalone tag.
                vars.discardEvent = true;
            }
        } else {
            throw new IllegalStateException("An element has been found with an associated processor of type " + processor.getClass().getName() + " which is neither a Tag Element Processor nor a Model Element Processor.");
        }
    }
    /*
         * QUEUE MODEL HANDLING (IF WE ARE THROTTLING)
         */
    if (this.throttleEngine && ((vars.modelAfter != null && vars.modelAfter.size() > 0) || (vars.modelBefore != null && vars.modelBefore.size() > 0))) {
        queueProcessable(new StandaloneElementTagModelProcessable(standaloneElementTag, vars, this.engineContext, this.modelController, this.flowController, this, this.next));
        return;
    }
    /*
         * PROCESS THE QUEUE BEFORE DELEGATING, if specified to do so
         */
    if (vars.modelBefore != null) {
        // This is never processable
        vars.modelBefore.process(this.next);
    }
    /*
         * PROCESS THE REST OF THE HANDLER CHAIN
         */
    if (!vars.discardEvent) {
        this.next.handleStandaloneElement(standaloneElementTag);
    }
    /*
         * PROCESS THE QUEUE, launching all the queued events
         */
    if (vars.modelAfter != null) {
        vars.modelAfter.process(vars.modelAfterProcessable ? this : this.next);
    }
    /*
         * DECREASE THE CONTEXT LEVEL once we have executed all the processors (and maybe a body if we added
         * one to the tag converting it into an open tag)
         */
    if (!this.throttleEngine || !this.flowController.stopProcessing) {
        if (this.engineContext != null) {
            this.engineContext.decreaseLevel();
        }
    } else {
        queueProcessable(this.decreaseContextLevelProcessable);
    }
}
Also used : IElementTagProcessor(org.thymeleaf.processor.element.IElementTagProcessor) IStandaloneElementTag(org.thymeleaf.model.IStandaloneElementTag) IText(org.thymeleaf.model.IText) IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) IElementModelProcessor(org.thymeleaf.processor.element.IElementModelProcessor) TemplateProcessingException(org.thymeleaf.exceptions.TemplateProcessingException)

Example 3 with IElementProcessor

use of org.thymeleaf.processor.element.IElementProcessor in project thymeleaf by thymeleaf.

the class ElementDefinitions method buildTextElementDefinition.

private static TextElementDefinition buildTextElementDefinition(final TemplateMode templateMode, final TextElementName name, final Set<IElementProcessor> elementProcessors) {
    // No need to use a list for sorting - the elementProcessors set has already been ordered
    final Set<IElementProcessor> associatedProcessors = new LinkedHashSet<IElementProcessor>(2);
    if (elementProcessors != null) {
        for (final IElementProcessor processor : elementProcessors) {
            if (processor.getTemplateMode() != templateMode) {
                // We are creating an element definition for a specific template mode
                continue;
            }
            final MatchingElementName matchingElementName = processor.getMatchingElementName();
            final MatchingAttributeName matchingAttributeName = processor.getMatchingAttributeName();
            if ((matchingElementName != null && matchingElementName.getTemplateMode() != templateMode) || (matchingAttributeName != null && matchingAttributeName.getTemplateMode() != templateMode)) {
                throw new ConfigurationException(templateMode + " processors must return " + templateMode + "element names and " + templateMode + " attribute names (processor: " + processor.getClass().getName() + ")");
            }
            if (matchingAttributeName != null && !matchingAttributeName.isMatchingAllAttributes()) {
                // (will be instead associated with the attribute).
                continue;
            }
            if (matchingElementName != null && !matchingElementName.matches(name)) {
                // Note that elementName == null means "apply to all processors"
                continue;
            }
            associatedProcessors.add(processor);
        }
    }
    // Build the final instance
    return new TextElementDefinition(name, associatedProcessors);
}
Also used : IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) LinkedHashSet(java.util.LinkedHashSet) MatchingElementName(org.thymeleaf.processor.element.MatchingElementName) MatchingAttributeName(org.thymeleaf.processor.element.MatchingAttributeName) ConfigurationException(org.thymeleaf.exceptions.ConfigurationException)

Example 4 with IElementProcessor

use of org.thymeleaf.processor.element.IElementProcessor in project thymeleaf by thymeleaf.

the class AbstractProcessableElementTag method computeProcessors.

private IElementProcessor[] computeProcessors() {
    final int associatedProcessorCount = (this.attributes != null ? this.attributes.getAssociatedProcessorCount() : 0);
    // If there are no processors associated with attributes, this is much easier
    if (this.attributes == null || associatedProcessorCount == 0) {
        return (this.elementDefinition.hasAssociatedProcessors ? this.elementDefinition.associatedProcessors : EMPTY_ASSOCIATED_PROCESSORS);
    }
    // At this point we know for sure there are processors associated with attributes
    final int elementProcessorCount = (this.elementDefinition.hasAssociatedProcessors ? this.elementDefinition.associatedProcessors.length : 0);
    IElementProcessor[] processors = new IElementProcessor[elementProcessorCount + associatedProcessorCount];
    if (elementProcessorCount > 0) {
        System.arraycopy(this.elementDefinition.associatedProcessors, 0, processors, 0, elementProcessorCount);
    }
    int idx = elementProcessorCount;
    int n = this.attributes.attributes.length;
    while (n-- != 0) {
        if (!this.attributes.attributes[n].definition.hasAssociatedProcessors) {
            continue;
        }
        final IElementProcessor[] attributeAssociatedProcessors = this.attributes.attributes[n].definition.associatedProcessors;
        for (int i = 0; i < attributeAssociatedProcessors.length; i++) {
            // We should never have duplicates. The same attribute can never appear twice in an element (parser
            // restrictions + the way this class's 'setAttribute' works), plus a specific processor instance can
            // never appear in more than one dialect, nor be applied to more than one attribute name.
            // Now for each processor, before adding it to the list, we must first determine whether it requires
            // a specific element name and, if so, confirm that it is the same as the name of the element these
            // attributes live at.
            final MatchingElementName matchingElementName = attributeAssociatedProcessors[i].getMatchingElementName();
            if (matchingElementName != null && !matchingElementName.matches(this.elementDefinition.elementName)) {
                continue;
            }
            // Just add the processor to the list
            processors[idx++] = attributeAssociatedProcessors[i];
        }
    }
    // due to the element name not matching. In such cases, we need to readjust the array size.
    if (idx < processors.length) {
        processors = Arrays.copyOf(processors, idx);
    }
    if (processors.length > 1) {
        Arrays.sort(processors, ProcessorComparators.PROCESSOR_COMPARATOR);
    }
    return processors;
}
Also used : IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) MatchingElementName(org.thymeleaf.processor.element.MatchingElementName)

Example 5 with IElementProcessor

use of org.thymeleaf.processor.element.IElementProcessor 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());
}
Also used : IEngineConfiguration(org.thymeleaf.IEngineConfiguration) ITextProcessor(org.thymeleaf.processor.text.ITextProcessor) IProcessingInstructionProcessor(org.thymeleaf.processor.processinginstruction.IProcessingInstructionProcessor) ArrayList(java.util.ArrayList) ITemplateBoundariesProcessor(org.thymeleaf.processor.templateboundaries.ITemplateBoundariesProcessor) Dialect01(org.thymeleaf.dialect.dialectwrapping.Dialect01) IDocTypeProcessor(org.thymeleaf.processor.doctype.IDocTypeProcessor) IElementProcessor(org.thymeleaf.processor.element.IElementProcessor) ICommentProcessor(org.thymeleaf.processor.comment.ICommentProcessor) TemplateEngine(org.thymeleaf.TemplateEngine) IXMLDeclarationProcessor(org.thymeleaf.processor.xmldeclaration.IXMLDeclarationProcessor) ICDATASectionProcessor(org.thymeleaf.processor.cdatasection.ICDATASectionProcessor) Test(org.junit.Test)

Aggregations

IElementProcessor (org.thymeleaf.processor.element.IElementProcessor)13 LinkedHashSet (java.util.LinkedHashSet)7 ConfigurationException (org.thymeleaf.exceptions.ConfigurationException)7 MatchingElementName (org.thymeleaf.processor.element.MatchingElementName)7 MatchingAttributeName (org.thymeleaf.processor.element.MatchingAttributeName)6 TemplateMode (org.thymeleaf.templatemode.TemplateMode)5 ArrayList (java.util.ArrayList)3 Test (org.junit.Test)2 TemplateProcessingException (org.thymeleaf.exceptions.TemplateProcessingException)2 IText (org.thymeleaf.model.IText)2 IProcessor (org.thymeleaf.processor.IProcessor)2 ICDATASectionProcessor (org.thymeleaf.processor.cdatasection.ICDATASectionProcessor)2 ICommentProcessor (org.thymeleaf.processor.comment.ICommentProcessor)2 IDocTypeProcessor (org.thymeleaf.processor.doctype.IDocTypeProcessor)2 IElementModelProcessor (org.thymeleaf.processor.element.IElementModelProcessor)2 IProcessingInstructionProcessor (org.thymeleaf.processor.processinginstruction.IProcessingInstructionProcessor)2 ITemplateBoundariesProcessor (org.thymeleaf.processor.templateboundaries.ITemplateBoundariesProcessor)2 ITextProcessor (org.thymeleaf.processor.text.ITextProcessor)2 IXMLDeclarationProcessor (org.thymeleaf.processor.xmldeclaration.IXMLDeclarationProcessor)2 EnumMap (java.util.EnumMap)1