All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.thymeleaf.engine.StandardModelFactory Maven / Gradle / Ivy

Go to download

Modern server-side Java template engine for both web and standalone environments

There is a newer version: 3.1.2.RELEASE
Show newest version
/*
 * =============================================================================
 *
 *   Copyright (c) 2011-2018, 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.engine;

import java.util.Arrays;
import java.util.Map;

import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.model.AttributeValueQuotes;
import org.thymeleaf.model.ICDATASection;
import org.thymeleaf.model.ICloseElementTag;
import org.thymeleaf.model.IComment;
import org.thymeleaf.model.IDocType;
import org.thymeleaf.model.IModel;
import org.thymeleaf.model.IModelFactory;
import org.thymeleaf.model.IOpenElementTag;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.model.IProcessingInstruction;
import org.thymeleaf.model.IStandaloneElementTag;
import org.thymeleaf.model.ITemplateEvent;
import org.thymeleaf.model.IText;
import org.thymeleaf.model.IXMLDeclaration;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.util.Validate;

/**
 *
 * @author Daniel Fernández
 * @since 3.0.0
 * 
 */
public class StandardModelFactory implements IModelFactory {

    private static final String[][] SYNTHETIC_INNER_WHITESPACES = new String[][] {
            new String[0],
            Attributes.DEFAULT_WHITE_SPACE_ARRAY,
            new String[] { Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE },
            new String[] { Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE },
            new String[] { Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE },
            new String[] { Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE, Attributes.DEFAULT_WHITE_SPACE }
    };


    private final IEngineConfiguration configuration;
    private final AttributeDefinitions attributeDefinitions;
    private final ElementDefinitions elementDefinitions;
    private final TemplateMode templateMode;



    public StandardModelFactory(final IEngineConfiguration configuration, final TemplateMode templateMode) {

        super();

        Validate.notNull(configuration, "Configuration cannot be null");
        Validate.notNull(configuration.getAttributeDefinitions(), "Attribute Definitions returned by Engine Configuration cannot be null");
        Validate.notNull(configuration.getElementDefinitions(), "Element Definitions returned by Engine Configuration cannot be null");
        Validate.notNull(templateMode, "Template Mode cannot be null");

        this.configuration = configuration;
        this.attributeDefinitions = this.configuration.getAttributeDefinitions();
        this.elementDefinitions = this.configuration.getElementDefinitions();
        this.templateMode = templateMode;

    }



    private void checkRestrictedEventForTextTemplateMode(final String eventClass) {
        if (this.templateMode.isText()) {
            throw new TemplateProcessingException(
                    "Events of class " + eventClass + " cannot be created in a text-type template " +
                    "mode (" + this.templateMode + ")");
        }
    }



    public IModel createModel() {
        return new Model(this.configuration, this.templateMode);
    }


    public IModel createModel(final ITemplateEvent event) {
        final Model model = new Model(this.configuration, this.templateMode);
        model.add(event);
        return model;
    }




    public IModel parse(final TemplateData ownerTemplate, final String template) {
        // We will be setting useCache to false because we don't want to pollute the cache with mere String
        // parsing done from here. Also, we are 'artificially' specifying it as nested even if we don't really
        // know if this fragment is exactly a nested text inside the template, but that's not really important...
        return this.configuration.getTemplateManager().parseString(ownerTemplate, template, 0, 0, this.templateMode, false);
    }




    public ICDATASection createCDATASection(final CharSequence content) {
        checkRestrictedEventForTextTemplateMode("CDATASection");
        return new CDATASection(content);
    }




    public IComment createComment(final CharSequence content) {
        checkRestrictedEventForTextTemplateMode("Comment");
        return new Comment(content);
    }




    public IDocType createHTML5DocType() {
        checkRestrictedEventForTextTemplateMode("DocType");
        return new DocType(null, null);
    }


    public IDocType createDocType(final String publicId, final String systemId) {
        checkRestrictedEventForTextTemplateMode("DocType");
        return new DocType(publicId, systemId);
    }


    public IDocType createDocType(
            final String keyword,
            final String elementName,
            final String publicId,
            final String systemId,
            final String internalSubset) {

        checkRestrictedEventForTextTemplateMode("DocType");
        return new DocType(keyword, elementName, publicId, systemId, internalSubset);
    }




    public IProcessingInstruction createProcessingInstruction(final String target, final String content) {
        checkRestrictedEventForTextTemplateMode("ProcessingInstruction");
        return new ProcessingInstruction(target, content);
    }




    public IText createText(final CharSequence text) {
        return new Text(text);
    }




    public IXMLDeclaration createXMLDeclaration(final String version, final String encoding, final String standalone) {
        checkRestrictedEventForTextTemplateMode("XMLDeclaration");
        return new XMLDeclaration(XMLDeclaration.DEFAULT_KEYWORD, version, encoding, standalone);
    }




    @Override
    public IStandaloneElementTag createStandaloneElementTag(final String elementName) {
        return createStandaloneElementTag(elementName, false, true);
    }


    @Override
    public IStandaloneElementTag createStandaloneElementTag(final String elementName, final String attributeName, final String attributeValue) {
        return createStandaloneElementTag(elementName, attributeName, attributeValue, false, true);
    }


    @Override
    public IStandaloneElementTag createStandaloneElementTag(final String elementName, final boolean synthetic, final boolean minimized) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        return new StandaloneElementTag(this.templateMode, elementDefinition, elementName, null, synthetic, minimized);
    }


    @Override
    public IStandaloneElementTag createStandaloneElementTag(final String elementName, final String attributeName, final String attributeValue, final boolean synthetic, final boolean minimized) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        final Attributes attributes = buildAttributes(new Attribute[] { buildAttribute(attributeName, attributeValue, null) });
        return new StandaloneElementTag(this.templateMode, elementDefinition, elementName, attributes, synthetic, minimized);
    }


    @Override
    public IStandaloneElementTag createStandaloneElementTag(final String elementName, final Map attributes, final AttributeValueQuotes attributeValueQuotes, final boolean synthetic, final boolean minimized) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        final Attributes attributesObj = buildAttributes(buildAttributeArray(attributes, attributeValueQuotes));
        return new StandaloneElementTag(this.templateMode, elementDefinition, elementName, attributesObj, synthetic, minimized);
    }




    @Override
    public IOpenElementTag createOpenElementTag(final String elementName) {
        return createOpenElementTag(elementName, false);
    }


    @Override
    public IOpenElementTag createOpenElementTag(final String elementName, final String attributeName, final String attributeValue) {
        return createOpenElementTag(elementName, attributeName, attributeValue, false);
    }


    @Override
    public IOpenElementTag createOpenElementTag(final String elementName, final boolean synthetic) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        return new OpenElementTag(this.templateMode, elementDefinition, elementName, null, synthetic);
    }


    @Override
    public IOpenElementTag createOpenElementTag(final String elementName, final String attributeName, final String attributeValue, final boolean synthetic) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        final Attributes attributes = buildAttributes(new Attribute[] { buildAttribute(attributeName, attributeValue, null) });
        return new OpenElementTag(this.templateMode, elementDefinition, elementName, attributes, synthetic);
    }


    @Override
    public IOpenElementTag createOpenElementTag(final String elementName, final Map attributes, final AttributeValueQuotes attributeValueQuotes, final boolean synthetic) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        final Attributes attributesObj = buildAttributes(buildAttributeArray(attributes, attributeValueQuotes));
        return new OpenElementTag(this.templateMode, elementDefinition, elementName, attributesObj, synthetic);
    }




    @Override
    public  T setAttribute(final T tag, final String attributeName, final String attributeValue) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) setAttribute((IOpenElementTag)tag, attributeName, attributeValue);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) setAttribute((IStandaloneElementTag)tag, attributeName, attributeValue);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }


    @Override
    public  T setAttribute(final T tag, final String attributeName, final String attributeValue, final AttributeValueQuotes attributeValueQuotes) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) setAttribute((IOpenElementTag)tag, attributeName, attributeValue, attributeValueQuotes);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) setAttribute((IStandaloneElementTag)tag, attributeName, attributeValue, attributeValueQuotes);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }


    @Override
    public  T replaceAttribute(final T tag, final AttributeName oldAttributeName, final String attributeName, final String attributeValue) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) replaceAttribute((IOpenElementTag)tag, oldAttributeName, attributeName, attributeValue);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) replaceAttribute((IStandaloneElementTag)tag, oldAttributeName, attributeName, attributeValue);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }


    @Override
    public  T replaceAttribute(final T tag, final AttributeName oldAttributeName, final String attributeName, final String attributeValue, final AttributeValueQuotes attributeValueQuotes) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) replaceAttribute((IOpenElementTag)tag, oldAttributeName, attributeName, attributeValue, attributeValueQuotes);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) replaceAttribute((IStandaloneElementTag)tag, oldAttributeName, attributeName, attributeValue, attributeValueQuotes);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }


    @Override
    public  T removeAttribute(final T tag, final String attributeName) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) removeAttribute((IOpenElementTag)tag, attributeName);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) removeAttribute((IStandaloneElementTag)tag, attributeName);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }


    @Override
    public  T removeAttribute(final T tag, final String prefix, final String name) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) removeAttribute((IOpenElementTag)tag, prefix, name);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) removeAttribute((IStandaloneElementTag)tag, prefix, name);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }


    @Override
    public  T removeAttribute(final T tag, final AttributeName attributeName) {
        if (tag == null) {
            return null;
        }
        if (tag instanceof IOpenElementTag) {
            return (T) removeAttribute((IOpenElementTag)tag, attributeName);
        }
        if (tag instanceof IStandaloneElementTag) {
            return (T) removeAttribute((IStandaloneElementTag)tag, attributeName);
        }
        throw new TemplateProcessingException("Unknown type of processable element tag: " + tag.getClass().getName());
    }




    private IStandaloneElementTag setAttribute(final IStandaloneElementTag standaloneElementTag, final String attributeName, final String attributeValue) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return setAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), attributeName, attributeValue);
        }
        return ((StandaloneElementTag) standaloneElementTag).setAttribute(this.attributeDefinitions, null, attributeName, attributeValue, null);
    }


    private IStandaloneElementTag setAttribute(final IStandaloneElementTag standaloneElementTag, final String attributeName, final String attributeValue, final AttributeValueQuotes attributeValueQuotes) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return setAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), attributeName, attributeValue, attributeValueQuotes);
        }
        return ((StandaloneElementTag) standaloneElementTag).setAttribute(this.attributeDefinitions, null, attributeName, attributeValue, attributeValueQuotes);
    }


    private IStandaloneElementTag replaceAttribute(final IStandaloneElementTag standaloneElementTag, final AttributeName oldAttributeName, final String attributeName, final String attributeValue) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return replaceAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), oldAttributeName, attributeName, attributeValue);
        }
        return ((StandaloneElementTag) standaloneElementTag).replaceAttribute(this.attributeDefinitions, oldAttributeName, null, attributeName, attributeValue, null);
    }


    private IStandaloneElementTag replaceAttribute(final IStandaloneElementTag standaloneElementTag, final AttributeName oldAttributeName, final String attributeName, final String attributeValue, final AttributeValueQuotes attributeValueQuotes) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return replaceAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), oldAttributeName, attributeName, attributeValue, attributeValueQuotes);
        }
        return ((StandaloneElementTag) standaloneElementTag).replaceAttribute(this.attributeDefinitions, oldAttributeName, null, attributeName, attributeValue, attributeValueQuotes);
    }


    private IStandaloneElementTag removeAttribute(final IStandaloneElementTag standaloneElementTag, final String attributeName) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return removeAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), attributeName);
        }
        return ((StandaloneElementTag) standaloneElementTag).removeAttribute(attributeName);
    }


    private IStandaloneElementTag removeAttribute(final IStandaloneElementTag standaloneElementTag, final String prefix, final String name) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return removeAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), prefix, name);
        }
        return ((StandaloneElementTag) standaloneElementTag).removeAttribute(prefix, name);
    }


    private IStandaloneElementTag removeAttribute(final IStandaloneElementTag standaloneElementTag, final AttributeName attributeName) {
        if (!(standaloneElementTag instanceof StandaloneElementTag)) {
            return removeAttribute(StandaloneElementTag.asEngineStandaloneElementTag(standaloneElementTag), attributeName);
        }
        return ((StandaloneElementTag) standaloneElementTag).removeAttribute(attributeName);
    }




    private IOpenElementTag setAttribute(final IOpenElementTag openElementTag, final String attributeName, final String attributeValue) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return setAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), attributeName, attributeValue);
        }
        return ((OpenElementTag) openElementTag).setAttribute(this.attributeDefinitions, null, attributeName, attributeValue, null);
    }


    private IOpenElementTag setAttribute(final IOpenElementTag openElementTag, final String attributeName, final String attributeValue, final AttributeValueQuotes attributeValueQuotes) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return setAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), attributeName, attributeValue, attributeValueQuotes);
        }
        return ((OpenElementTag) openElementTag).setAttribute(this.attributeDefinitions, null, attributeName, attributeValue, attributeValueQuotes);
    }


    private IOpenElementTag replaceAttribute(final IOpenElementTag openElementTag, final AttributeName oldAttributeName, final String attributeName, final String attributeValue) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return replaceAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), oldAttributeName, attributeName, attributeValue);
        }
        return ((OpenElementTag) openElementTag).replaceAttribute(this.attributeDefinitions, oldAttributeName, null, attributeName, attributeValue, null);
    }


    private IOpenElementTag replaceAttribute(final IOpenElementTag openElementTag, final AttributeName oldAttributeName, final String attributeName, final String attributeValue, final AttributeValueQuotes attributeValueQuotes) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return replaceAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), oldAttributeName, attributeName, attributeValue, attributeValueQuotes);
        }
        return ((OpenElementTag) openElementTag).replaceAttribute(this.attributeDefinitions, oldAttributeName, null, attributeName, attributeValue, attributeValueQuotes);
    }


    private IOpenElementTag removeAttribute(final IOpenElementTag openElementTag, final String attributeName) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return removeAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), attributeName);
        }
        return ((OpenElementTag) openElementTag).removeAttribute(attributeName);
    }


    private IOpenElementTag removeAttribute(final IOpenElementTag openElementTag, final String prefix, final String name) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return removeAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), prefix, name);
        }
        return ((OpenElementTag) openElementTag).removeAttribute(prefix, name);
    }


    private IOpenElementTag removeAttribute(final IOpenElementTag openElementTag, final AttributeName attributeName) {
        if (!(openElementTag instanceof OpenElementTag)) {
            return removeAttribute(OpenElementTag.asEngineOpenElementTag(openElementTag), attributeName);
        }
        return ((OpenElementTag) openElementTag).removeAttribute(attributeName);
    }




    @Override
    public ICloseElementTag createCloseElementTag(final String elementName) {
        return createCloseElementTag(elementName, false, false);
    }


    @Override
    public ICloseElementTag createCloseElementTag(final String elementName, final boolean synthetic, final boolean unmatched) {
        final ElementDefinition elementDefinition = this.elementDefinitions.forName(this.templateMode, elementName);
        return new CloseElementTag(this.templateMode, elementDefinition, elementName, null, synthetic, unmatched);
    }




    private Attribute buildAttribute(final String name, final String value, final AttributeValueQuotes quotes) {
        final AttributeDefinition attributeDefinition = this.attributeDefinitions.forName(this.templateMode, name);
        return new Attribute(attributeDefinition, name, Attribute.DEFAULT_OPERATOR, value, quotes, null, -1, -1);
    }


    private Attribute[] buildAttributeArray(final Map attributes, final AttributeValueQuotes quotes) {
        if (attributes == null || attributes.size() == 0) {
            return Attributes.EMPTY_ATTRIBUTE_ARRAY;
        }
        int i = 0;
        final Attribute[] newAttributes = new Attribute[attributes.size()];
        for (final Map.Entry attributesEntry : attributes.entrySet()) {
            newAttributes[i++] = buildAttribute(attributesEntry.getKey(), attributesEntry.getValue(), quotes);
        }
        return newAttributes;
    }


    private Attributes buildAttributes(final Attribute[] attributeArray) {
        if (attributeArray == null || attributeArray.length == 0) {
            return Attributes.EMPTY_ATTRIBUTES;
        }
        final String[] innerWhiteSpaces;
        if (attributeArray.length < SYNTHETIC_INNER_WHITESPACES.length) {
            innerWhiteSpaces = SYNTHETIC_INNER_WHITESPACES[attributeArray.length];
        } else {
            innerWhiteSpaces = new String[attributeArray.length];
            Arrays.fill(innerWhiteSpaces, Attributes.DEFAULT_WHITE_SPACE);
        }
        return new Attributes(attributeArray, innerWhiteSpaces);
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy