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

org.zodiac.template.base.impl.TemplateServiceImpl Maven / Gradle / Ivy

There is a newer version: 1.6.8
Show newest version
package org.zodiac.template.base.impl;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.zodiac.core.configuration.ProductionModeAware;
import org.zodiac.core.service.AbstractService;
import org.zodiac.sdk.toolkit.util.AssertUtil;
import org.zodiac.sdk.toolkit.util.collection.CollAndMapUtil;
import org.zodiac.sdk.toolkit.util.file.FileToolUtil;
import org.zodiac.sdk.toolkit.util.lang.StrUtil;
import org.zodiac.template.base.TemplateContext;
import org.zodiac.template.base.TemplateEngine;
import org.zodiac.template.base.TemplateException;
import org.zodiac.template.base.TemplateNotFoundException;
import org.zodiac.template.base.TemplateService;
import org.zodiac.template.base.constants.TemplateConstants;

public class TemplateServiceImpl extends AbstractService
    implements TemplateService, ProductionModeAware {
    /*engineName -> engine*/
    private Map engines;
    /*ext -> engine*/
    private Map engineMappings;
    /*ext -> engineName*/
    private Map engineNameMappings;
    private String defaultExtension = TemplateConstants.DEFAULT_DEFAULT_EXTENSION;
    private boolean searchExtensions;
    private boolean searchLocalizedTemplates;
    private TemplateSearchingStrategy[] strategies;
    private Boolean cacheEnabled;
    private boolean productionMode = true;
    private Map matchedTemplates;

    public TemplateServiceImpl() {
    }

    public TemplateServiceImpl setEngines(Map engines) {
        this.engines = engines;
        return this;
    }

    public TemplateServiceImpl setEngineNameMappings(Map engineNameMappings) {
        this.engineNameMappings = engineNameMappings;
        return this;
    }

    public TemplateServiceImpl setDefaultExtension(String defaultExtension) {
        this.defaultExtension = defaultExtension;
        return this;
    }

    public TemplateServiceImpl setSearchExtensions(boolean searchExtensions) {
        this.searchExtensions = searchExtensions;
        return this;
    }

    public TemplateServiceImpl setSearchLocalizedTemplates(boolean searchLocalizedTemplates) {
        this.searchLocalizedTemplates = searchLocalizedTemplates;
        return this;
    }

    public Boolean isCacheEnabled() {
        return cacheEnabled;
    }

    public TemplateServiceImpl setCacheEnabled(Boolean cacheEnabled) {
        this.cacheEnabled = cacheEnabled;
        return this;
    }

    public boolean isProductionMode() {
        return productionMode;
    }

    public void setProductionMode(boolean productionMode) {
        this.productionMode = productionMode;
    }

    @Override
    protected void init() {
        if (engines == null) {
            engines = CollAndMapUtil.map();
        }

        if (engines.isEmpty()) {
            getLogger().warn("No Template Engine registered for TemplateService: id={}", getBeanName());
        }

        if (cacheEnabled == null) {
            /*如果未指定cacheEnabled,则默认当productionMode时,打开cache。*/
            cacheEnabled = productionMode;
        }

        if (cacheEnabled) {
            matchedTemplates = CollAndMapUtil.concurrentMap();
        }

        Set remappedNames = CollAndMapUtil.set();
        engineMappings = CollAndMapUtil.treeMap();

        /*生成engineMappings。*/
        if (engineNameMappings != null) {
            for (Map.Entry entry : engineNameMappings.entrySet()) {
                String ext = entry.getKey();
                String engineName = entry.getValue();

                AssertUtil.assertTrue(StrUtil.isNotEmpty(ext) && !ext.startsWith("."), "Invalid extension: %s", ext);
                AssertUtil.assertTrue(engines.containsKey(engineName),
                    "TemplateEngine \"%s\" not defined. Defined names: %s", engineName, engines.keySet());

                remappedNames.add(engineName);
                engineMappings.put(ext, engines.get(engineName));

                getLogger().debug("Template Name \"*.{}\" mapped to Template Engine: {}", ext, engineName);
            }

            engineNameMappings = null;
        }

        /*对于没有指定mapping的engine,取得其默认后缀。*/
        for (Map.Entry entry : engines.entrySet()) {
            String engineName = entry.getKey();
            TemplateEngine engine = entry.getValue();

            if (!remappedNames.contains(engineName)) {
                String[] exts = engine.getDefaultExtensions();

                for (String ext : exts) {
                    ext = FileToolUtil.normalizeExtension(ext);

                    AssertUtil.assertNotNull(ext, "Default extensions for engine: %s", engine);

                    engineMappings.put(ext, engine);

                    getLogger().debug("Template Name \"*.{}\" mapped to Template Engine: {}", ext, engineName);
                }
            }
        }

        /*Searching strategies.*/
        defaultExtension = FileToolUtil.normalizeExtension(defaultExtension);
        List strategyList = CollAndMapUtil.linkedList();
        if (defaultExtension != null) {
            strategyList.add(new DefaultExtensionStrategy(defaultExtension));
        }
        if (searchExtensions) {
            strategyList.add(new SearchExtensionsStrategy(getSupportedExtensions()));
        }
        if (searchLocalizedTemplates) {
            strategyList.add(new SearchLocalizedTemplatesStrategy());
        }
        strategies = strategyList.toArray(new TemplateSearchingStrategy[strategyList.size()]);
    }

    /**
     * 取得指定模板名后缀对应的engine。
     * 
     * @param engineName 引擎名称
     * @return 模板引擎
     */
    public TemplateEngine getEngineOfName(String engineName) {
        return engines.get(engineName);
    }

    /**
     * 取得指定模板名后缀对应的engine。
     * 
     * @param extension 扩展名
     * @return 模板引擎
     */
    public TemplateEngine getTemplateEngine(String extension) {
        if (extension == null) {
            return null; // prevent treemap from throwing npe
        }
        return engineMappings.get(extension);
    }

    /**
     * 取得所有被登记的文件名后缀。
     * 
     * @return 扩展名列表
     */
    public String[] getSupportedExtensions() {
        return engineMappings.keySet().toArray(new String[engineMappings.size()]);
    }

    /**
     * 判断模板是否存在。
     * 
     * @param templateName 模板名称
     * @return 是对存在
     */
    public boolean exists(String templateName) {
        try {
            findTemplate(templateName);
            return true;
        } catch (TemplateNotFoundException e) {
            return false;
        }
    }

    /**
     * 渲染模板,并以字符串的形式取得渲染的结果。
     * 
     * @param templateName 模板名称
     * @param context 上下文
     * @return 内容
     * @throws TemplateException TemplateException
     * @throws IOException IOException
     */
    public String getText(String templateName, TemplateContext context) throws TemplateException, IOException {
        TemplateMatchResult result = findTemplate(templateName);
        TemplateEngine engine = AssertUtil.assertNotNull(result.getEngine(), "templateEngine");
        return engine.getText(result.getTemplateName(), context);
    }

    /**
     * @param templateName 模板名称
     * @param context 上下文
     * @param ostream 输出流
     * @throws TemplateException TemplateException
     * @throws IOException IOException
     */
    public void writeTo(String templateName, TemplateContext context, OutputStream ostream)
        throws TemplateException, IOException {
        TemplateMatchResult result = findTemplate(templateName);
        TemplateEngine engine = AssertUtil.assertNotNull(result.getEngine(), "templateEngine");
        engine.writeTo(result.getTemplateName(), context, ostream);
    }

    /**
     * 渲染模板,并将渲染的结果送到字符输出流中。
     * param templateName 模板名称
     * @param context 上下文
     * @param writer 输出流
     * @throws TemplateException TemplateException
     * @throws IOException IOException
     */
    public void writeTo(String templateName, TemplateContext context, Writer writer)
        throws TemplateException, IOException {
        TemplateMatchResult result = findTemplate(templateName);
        TemplateEngine engine = AssertUtil.assertNotNull(result.getEngine(), "templateEngine");
        engine.writeTo(result.getTemplateName(), context, writer);
    }

    /**
     * 查找指定名称的模板。
     * @param templateName 模板名称
     * @return 模板查找结果
     */
    TemplateMatchResult findTemplate(String templateName) {
        assertInitialized();
        TemplateKey key = new TemplateKey(templateName, strategies);
        TemplateMatchResult result;
        if (cacheEnabled) {
            result = matchedTemplates.get(key);
            if (result != null) {
                return result;
            }
        }

        TemplateMatcher matcher = new TemplateMatcher(key) {
            private int i;
            @Override
            public boolean findTemplate() {
                boolean found = false;
                /*保存状态,假如没有匹配,则恢复状态*/
                String savedTemplateNameWithoutExtension = getTemplateNameWithoutExtension();
                String savedExtension = getExtension();
                TemplateEngine savedEngine = getEngine();
                int savedStrategyIndex = i;
                try {
                    if (i < strategies.length) {
                        found = strategies[i++].findTemplate(this);
                    } else {
                        found = findTemplateInTemplateEngine(this);
                    }
                } finally {
                    if (!found) {
                        /*恢复状态,以便尝试其它平级strategies*/
                        setTemplateNameWithoutExtension(savedTemplateNameWithoutExtension);
                        setExtension(savedExtension);
                        setEngine(savedEngine);
                        i = savedStrategyIndex;
                    }
                }
                return found;
            }
        };
        if (!matcher.findTemplate()) {
            throw new TemplateNotFoundException(
                "Could not find template \"" + matcher.getOriginalTemplateName() + "\"");
        }
        if (cacheEnabled) {
            result = new TemplateMatchResultImpl(matcher.getTemplateName(), matcher.getEngine());
            matchedTemplates.put(key, result);
        } else {
            result = matcher;
        }
        return result;
    }

    /* 查找模板的最终strategy结点。 */
    private boolean findTemplateInTemplateEngine(TemplateMatcher matcher) {
        TemplateEngine engine = getTemplateEngine(matcher.getExtension());
        matcher.setEngine(engine);
        if (engine == null) {
            return false;
        }
        String templateName = matcher.getTemplateName();
        getLogger().trace("Searching for template \"{}\" using {}", templateName, engine);
        return engine.exists(templateName);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy