Package org.thymeleaf

Source Code of org.thymeleaf.DialectConfiguration

/*
* =============================================================================
*
*   Copyright (c) 2011-2014, 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.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.thymeleaf.dialect.IDialect;
import org.thymeleaf.doctype.resolution.IDocTypeResolutionEntry;
import org.thymeleaf.doctype.translation.IDocTypeTranslation;
import org.thymeleaf.dom.Node;
import org.thymeleaf.exceptions.ConfigurationException;
import org.thymeleaf.exceptions.NotInitializedException;
import org.thymeleaf.processor.IAttributeNameProcessorMatcher;
import org.thymeleaf.processor.IElementNameProcessorMatcher;
import org.thymeleaf.processor.IProcessor;
import org.thymeleaf.processor.IProcessorMatcher;
import org.thymeleaf.processor.ProcessorAndContext;
import org.thymeleaf.processor.ProcessorMatchingContext;
import org.thymeleaf.util.Validate;

/**
* <p>
*   Configuration class for a specific {@link IDialect}.
* </p>
* <p>
*   Except for testing purposes, there is no reason why a user might need to use this
*   class directly.
* </p>
*
* @author Daniel Fern&aacute;ndez
*
* @since 1.0
*
*/
public final class DialectConfiguration {
   
    private final String prefix;
    private final IDialect dialect;
   
    private Set<IDocTypeTranslation> docTypeTranslations;
    private Set<IDocTypeResolutionEntry> docTypeResolutionEntries;
   
    private Set<IProcessor> processors;
   
    private Map<String,Set<ProcessorAndContext>> specificProcessorsByElementName;
    private Map<String,Set<ProcessorAndContext>> specificProcessorsByAttributeName;
    private Map<Class<? extends Node>, Set<ProcessorAndContext>> nonSpecificProcessorsByNodeClass;
   
    private Map<String,Object> executionAttributes;
   
    private volatile boolean initialized;

   
   

   
    DialectConfiguration(final String prefix, final IDialect dialect) {
        super();
        // Prefix CAN be null
        Validate.notNull(dialect, "Dialect cannot be null");
        this.prefix = prefix;
        this.dialect = dialect;
        this.initialized = false;
    }



   
   
    private boolean isInitialized() {
        return this.initialized;
    }
   
    private void checkInitialized() {
        if (!isInitialized()) {
            throw new NotInitializedException("Configuration has not been initialized");
        }
    }
   
   
   
   
   
   
    public synchronized void initialize() {
   
        if (!isInitialized()) {
           
            /*
             * Initializing processors
             */
            this.processors = new LinkedHashSet<IProcessor>(this.dialect.getProcessors());
            this.processors = Collections.unmodifiableSet(this.processors);
            Validate.containsNoNulls(this.processors, "Processor set can contain no nulls (dialect: " + this.dialect.getClass().getName() + ")");
           
            final ProcessorMatchingContext context =
                    new ProcessorMatchingContext(this.dialect, this.prefix);
           
            final Map<String,Set<ProcessorAndContext>> newSpecificProcessorsByElementName = new HashMap<String,Set<ProcessorAndContext>>(20);
            final Map<String,Set<ProcessorAndContext>> newSpecificProcessorsByAttributeName = new HashMap<String,Set<ProcessorAndContext>>(20);
            final Map<Class<? extends Node>, Set<ProcessorAndContext>> newNonSpecificProcessorsByNodeClass = new HashMap<Class<? extends Node>, Set<ProcessorAndContext>>(20);
           
            for (final IProcessor processor : this.processors) {

                final IProcessorMatcher<? extends Node> processorMatcher = processor.getMatcher();
                if (processorMatcher == null) {
                    throw new ConfigurationException(
                            "Processor of class \"" + processor.getClass().getName() + "\" " +
                            "returned null processor matcher.");
                }
               
                if (processorMatcher instanceof IElementNameProcessorMatcher) {
                    // Processor will be indexed as "specific" for one or more element names
                   
                    final String[] elementNames = ((IElementNameProcessorMatcher) processorMatcher).getElementNames(context);
                    if (elementNames == null) {
                        throw new ConfigurationException(
                                "Processor of class \"" + processor.getClass().getName() + "\" " +
                                "returned a null element name as a part of its applicability specifications.");
                    }

                    for (final String elementName : elementNames) {
                        Set<ProcessorAndContext> processorsForElementName = newSpecificProcessorsByElementName.get(elementName);
                        if (processorsForElementName == null) {
                            processorsForElementName = new HashSet<ProcessorAndContext>(20);
                            newSpecificProcessorsByElementName.put(elementName, processorsForElementName);
                        }
                        processorsForElementName.add(new ProcessorAndContext(processor, context));
                    }


                }
               
                if (processorMatcher instanceof IAttributeNameProcessorMatcher) {
                    // Processor will be indexed as "specific" for one or more attribute names
                   
                   
                    final String[] attributeNames = ((IAttributeNameProcessorMatcher) processorMatcher).getAttributeNames(context);
                    if (attributeNames == null) {
                        throw new ConfigurationException(
                                "Processor of class \"" + processor.getClass().getName() + "\" " +
                                "returned a null attribute name as a part of its applicability specifications.");
                    }

                    for (final String attributeName : attributeNames) {
                        Set<ProcessorAndContext> processorsForAttributeName = newSpecificProcessorsByAttributeName.get(attributeName);
                        if (processorsForAttributeName == null) {
                            processorsForAttributeName = new HashSet<ProcessorAndContext>(20);
                            newSpecificProcessorsByAttributeName.put(attributeName, processorsForAttributeName);
                        }
                        processorsForAttributeName.add(new ProcessorAndContext(processor, context));
                    }

                }
               
                if (!(processorMatcher instanceof IElementNameProcessorMatcher) && !(processorMatcher instanceof IAttributeNameProcessorMatcher)) {
                   
                    final Class<? extends Node> appliesTo = processorMatcher.appliesTo();
                       
                    Set<ProcessorAndContext> processorsForNodeClass = newNonSpecificProcessorsByNodeClass.get(appliesTo);
                    if (processorsForNodeClass == null) {
                        processorsForNodeClass = new HashSet<ProcessorAndContext>(20);
                        newNonSpecificProcessorsByNodeClass.put(appliesTo, processorsForNodeClass);
                    }
                   
                    processorsForNodeClass.add(new ProcessorAndContext(processor, context));

                }
               
               
               
            }
           
            this.specificProcessorsByElementName = Collections.unmodifiableMap(newSpecificProcessorsByElementName);
            this.specificProcessorsByAttributeName = Collections.unmodifiableMap(newSpecificProcessorsByAttributeName);
            this.nonSpecificProcessorsByNodeClass = Collections.unmodifiableMap(newNonSpecificProcessorsByNodeClass);           

           
            /*
             * Initializing execution arguments
             */
            this.executionAttributes = new HashMap<String, Object>(5,1.0f);
            this.executionAttributes.putAll(this.dialect.getExecutionAttributes());

           
           
            /*
             * Configuring DOCTYPE translations
             */
            this.docTypeTranslations =
                Collections.unmodifiableSet(new LinkedHashSet<IDocTypeTranslation>(this.dialect.getDocTypeTranslations()));
            Validate.containsNoNulls(this.docTypeTranslations, "Document Type translations can contain no nulls");

            validateDocTypeTranslations();
           
           
            /*
             * Configuring DOCTYPE resolution entries
             */
            this.docTypeResolutionEntries =
                Collections.unmodifiableSet(new LinkedHashSet<IDocTypeResolutionEntry>(this.dialect.getDocTypeResolutionEntries()));
            Validate.containsNoNulls(this.docTypeResolutionEntries, "Document Type resolution entries can contain no nulls");

            validateDocTypeResolutionEntries();
           
           
           
            /*
             * Mark as initialized
             */
            this.initialized = true;
           
        }
      
    }

   
   
    public synchronized IDialect getDialect() {
        return this.dialect;
    }
   
   
   
    public String getPrefix() {
        return this.prefix;
    }


   

   
    Set<IProcessor> getProcessors() {
        return this.processors;
    }


   
    Map<String,Set<ProcessorAndContext>> unsafeGetSpecificProcessorsByAttributeName() {
        return this.specificProcessorsByAttributeName;
    }
   
    Map<String,Set<ProcessorAndContext>> unsafeGetSpecificProcessorsByElementName() {
        return this.specificProcessorsByElementName;
    }
   
    Map<Class<? extends Node>, Set<ProcessorAndContext>> unsafeGetNonSpecificProcessorsByNodeClass() {
        return this.nonSpecificProcessorsByNodeClass;
    }
   
   
   
   
   

   
    Map<String,Object> getExecutionAttributes() {
        return this.executionAttributes;
    }
   

   
   
   
   
   
   
    private void validateDocTypeTranslations() {
       
        for (final IDocTypeTranslation translation : this.docTypeTranslations) {
           
            if (translation.getSourcePublicID() == null) {
                throw new ConfigurationException(
                        "Translation specifies a null Source PUBLICID. " +
                        "Document Type identifiers should never be null. " +
                        "Use \"NONE\" if you want to specify a non-existent identifier");
            }
            if (translation.getSourceSystemID() == null) {
                throw new ConfigurationException(
                        "Translation specifies a null Source SYSTEMID. " +
                        "Document Type identifiers should never be null. " +
                        "Use \"NONE\" if you want to specify a non-existent identifier");
            }
            if (translation.getTargetPublicID() == null) {
                throw new ConfigurationException(
                        "Translation specifies a null Target PUBLICID. " +
                        "Document Type identifiers should never be null. " +
                        "Use \"NONE\" if you want to specify a non-existent identifier");
            }
            if (translation.getTargetSystemID() == null) {
                throw new ConfigurationException(
                        "Translation specifies a null Target SYSTEMID. " +
                        "Document Type identifiers should never be null. " +
                        "Use \"NONE\" if you want to specify a non-existent identifier");
            }
           
        }
       
    }

   
    private void validateDocTypeResolutionEntries() {
       
        final Set<IDocTypeResolutionEntry> entriesAlreadyValidated = new LinkedHashSet<IDocTypeResolutionEntry>(10,1.0f);
        for (final IDocTypeResolutionEntry entry : this.docTypeResolutionEntries) {
           
            for (final IDocTypeResolutionEntry validatedEntry : entriesAlreadyValidated) {
                if (
                    (
                      validatedEntry.getPublicID().matches(entry.getPublicID())
                      &&
                      validatedEntry.getSystemID().matches(entry.getSystemID())
                    )
                    ||
                    (
                      entry.getPublicID().matches(validatedEntry.getPublicID())
                      &&
                      entry.getSystemID().matches(validatedEntry.getSystemID())
                    )
                  ) {
                    throw new ConfigurationException(
                            "Dialect specifies at least a couple of Document type resolution " +
                            "entries that would match each other, which would render resolution " +
                            "unpredictable");
                }
            }
           
            entriesAlreadyValidated.add(entry);
           
        }
       
    }

   
   
}
TOP

Related Classes of org.thymeleaf.DialectConfiguration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.