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

org.lastaflute.thymeleaf.dialect.LastaThymeleafDialect Maven / Gradle / Ivy

/*
 * Copyright 2015-2024 the original author or authors.
 *
 * 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.lastaflute.thymeleaf.dialect;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.dbflute.util.DfCollectionUtil;
import org.lastaflute.thymeleaf.customizer.ThymeleafAdditionalExpressionResource;
import org.lastaflute.thymeleaf.customizer.ThymeleafAdditionalExpressionSetupper;
import org.lastaflute.thymeleaf.expression.ClassificationExpressionObject;
import org.lastaflute.thymeleaf.expression.HandyDateExpressionObject;
import org.lastaflute.thymeleaf.processor.factory.LastaProcessorFactory;
import org.thymeleaf.context.IExpressionContext;
import org.thymeleaf.dialect.AbstractProcessorDialect;
import org.thymeleaf.dialect.IExpressionObjectDialect;
import org.thymeleaf.expression.IExpressionObjectFactory;
import org.thymeleaf.processor.IProcessor;

/**
 * Lasta Thymeleaf Dialect.
 * @author schatten
 * @author jflute
 * @author p1us2er0
 */
public class LastaThymeleafDialect extends AbstractProcessorDialect implements IExpressionObjectDialect {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    public static final String LASTA_THYMELEAF_DIALECT_PREFIX = "la";

    protected static final String EXPRESSION_OBJECT_CLASSIFICATION = "cls";
    protected static final String EXPRESSION_OBJECT_HANDY = "handy";

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final Set allExpressionObjectNames;
    protected final Set cacheableExpressionObjectNames;
    protected final HandyDateExpressionObject handyDateExpressionObject;
    protected final LastaExpressionObjectFactory expressionObjectFactory;
    protected final Set additionalProcessors = new LinkedHashSet();

    protected ThymeleafAdditionalExpressionSetupper additionalExpressionSetupper; // null allowed
    protected Map additionalExpressionObjectMap; // not null after initialization (lazy-loaded)

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public LastaThymeleafDialect() {
        super("lasta", LASTA_THYMELEAF_DIALECT_PREFIX, 1000);
        allExpressionObjectNames = prepareAllExpressionObjectNames();
        cacheableExpressionObjectNames = prepareCacheableExpressionObjectNames();
        handyDateExpressionObject = newHandyDateExpressionObject();
        expressionObjectFactory = newLastaExpressionObjectFactory();
    }

    protected Set prepareAllExpressionObjectNames() {
        return DfCollectionUtil.newHashSet(EXPRESSION_OBJECT_CLASSIFICATION, EXPRESSION_OBJECT_HANDY);
    }

    protected Set prepareCacheableExpressionObjectNames() {
        return DfCollectionUtil.newHashSet();
    }

    protected HandyDateExpressionObject newHandyDateExpressionObject() {
        return new HandyDateExpressionObject();
    }

    protected LastaExpressionObjectFactory newLastaExpressionObjectFactory() {
        return new LastaExpressionObjectFactory();
    }

    // -----------------------------------------------------
    //                                                Option
    //                                                ------
    public LastaThymeleafDialect additionalExpression(ThymeleafAdditionalExpressionSetupper additionalExpressionSetupper) {
        if (additionalExpressionSetupper == null) {
            throw new IllegalArgumentException("The argument 'additionalExpressionSetupper' should not be null.");
        }
        this.additionalExpressionSetupper = additionalExpressionSetupper;
        return this;
    }

    public LastaThymeleafDialect additionalProcessor(IProcessor processor) {
        if (processor == null) {
            throw new IllegalArgumentException("The argument 'processor' should not be null.");
        }
        this.additionalProcessors.add(processor);
        return this;
    }

    // ===================================================================================
    //                                                                   Expression Object
    //                                                                   =================
    @Override
    public IExpressionObjectFactory getExpressionObjectFactory() { // only once called when first access
        return expressionObjectFactory;
    }

    public class LastaExpressionObjectFactory implements IExpressionObjectFactory {

        @Override
        public Set getAllExpressionObjectNames() {
            initializeAdditionalExpressionIfNeeds(); // reflecting the names set to additional expressions
            return allExpressionObjectNames;
        }

        @Override
        public Object buildObject(IExpressionContext context, String expressionObjectName) {
            if ("cls".equals(expressionObjectName)) {
                return newClassificationExpressionObject(context);
            } else if ("handy".equals(expressionObjectName)) {
                return handyDateExpressionObject;
            }
            initializeAdditionalExpressionIfNeeds(); // preparing the object map
            final Object additionalObject = additionalExpressionObjectMap.get(expressionObjectName);
            if (additionalObject != null) {
                return additionalObject;
            }
            return null;
        }

        @Override
        public boolean isCacheable(String expressionObjectName) {
            // if not specified, false for safety
            return cacheableExpressionObjectNames.contains(expressionObjectName);
        }
    }

    protected ClassificationExpressionObject newClassificationExpressionObject(IExpressionContext context) {
        return new ClassificationExpressionObject(context);
    }

    protected ThymeleafAdditionalExpressionResource newThymeleafCustomExpressionResource() {
        return new ThymeleafAdditionalExpressionResource();
    }

    protected void initializeAdditionalExpressionIfNeeds() {
        if (additionalExpressionObjectMap != null) {
            return;
        }
        synchronized (this) {
            if (additionalExpressionObjectMap != null) {
                return;
            }
            if (additionalExpressionSetupper != null) {
                final ThymeleafAdditionalExpressionResource resource = newThymeleafCustomExpressionResource();
                additionalExpressionSetupper.setup(resource);
                final Map expressionObjectMap = resource.getExpressionObjectMap(); // read-only
                expressionObjectMap.keySet().forEach(name -> {
                    allExpressionObjectNames.add(name); // required since thymeleaf3
                });
                additionalExpressionObjectMap = expressionObjectMap;
                cacheableExpressionObjectNames.addAll(resource.getCacheableExpressionObjectNames());
            } else {
                additionalExpressionObjectMap = Collections.emptyMap();
            }
        }
    }

    // ===================================================================================
    //                                                                  Embedded Processor
    //                                                                  ==================
    @Override
    public Set getProcessors(String dialectPrefix) { // only once called when first access
        final Set processors = createLastaProcessorsSet();
        processors.addAll(getAdditionalProcessors());
        return processors;
    }

    protected Set createLastaProcessorsSet() {
        return newLastaProcessorFactory(LASTA_THYMELEAF_DIALECT_PREFIX).createLastaProcessorsSet();
    }

    protected LastaProcessorFactory newLastaProcessorFactory(String dialectPrefix) {
        return new LastaProcessorFactory(dialectPrefix);
    }

    public Set getAdditionalProcessors() { // as accessor
        return Collections.unmodifiableSet(additionalProcessors);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy