Package com.alibaba.citrus.service.template.impl

Source Code of com.alibaba.citrus.service.template.impl.TemplateServiceImpl

/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.service.template.impl;

import static com.alibaba.citrus.util.Assert.*;
import static com.alibaba.citrus.util.CollectionUtil.*;
import static com.alibaba.citrus.util.FileUtil.*;
import static com.alibaba.citrus.util.StringUtil.*;

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 com.alibaba.citrus.service.AbstractService;
import com.alibaba.citrus.service.configuration.ProductionModeAware;
import com.alibaba.citrus.service.template.TemplateContext;
import com.alibaba.citrus.service.template.TemplateEngine;
import com.alibaba.citrus.service.template.TemplateException;
import com.alibaba.citrus.service.template.TemplateNotFoundException;
import com.alibaba.citrus.service.template.TemplateService;

/**
* 实现<code>TemplateService</code>
*
* @author Michael Zhou
*/
public class TemplateServiceImpl extends AbstractService<TemplateService> implements TemplateService,
                                                                                     ProductionModeAware {
    private Map<String, TemplateEngine> engines; // engineName -> engine
    private Map<String, TemplateEngine> engineMappings; // ext -> engine
    private Map<String, String>         engineNameMappings; // ext -> engineName
    private String                      defaultExtension;
    private boolean                     searchExtensions;
    private boolean                     searchLocalizedTemplates;
    private TemplateSearchingStrategy[] strategies;
    private Boolean                     cacheEnabled;
    private boolean productionMode = true;
    private Map<TemplateKey, TemplateMatchResult> matchedTemplates;

    public void setEngines(Map<String, TemplateEngine> engines) {
        this.engines = engines;
    }

    public void setEngineNameMappings(Map<String, String> engineNameMappings) {
        this.engineNameMappings = engineNameMappings;
    }

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

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

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

    public Boolean isCacheEnabled() {
        return cacheEnabled;
    }

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

    public boolean isProductionMode() {
        return productionMode;
    }

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

    /** 初始化service。 */
    @Override
    protected void init() {
        if (engines == null) {
            engines = createHashMap();
        }

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

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

        if (cacheEnabled) {
            matchedTemplates = createConcurrentHashMap();
        }

        Set<String> remappedNames = createHashSet();
        engineMappings = createTreeMap();

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

                assertTrue(!isEmpty(ext) && !ext.startsWith("."), "Invalid extension: %s", ext);
                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<String, TemplateEngine> entry : engines.entrySet()) {
            String engineName = entry.getKey();
            TemplateEngine engine = entry.getValue();

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

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

                    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 = normalizeExtension(defaultExtension);

        List<TemplateSearchingStrategy> strategyList = createLinkedList();

        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。 */
    public TemplateEngine getEngineOfName(String engineName) {
        return engines.get(engineName);
    }

    /** 取得指定模板名后缀对应的engine。 */
    public TemplateEngine getTemplateEngine(String extension) {
        if (extension == null) {
            return null; // prevent treemap from throwing npe
        }

        return engineMappings.get(extension);
    }

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

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

    /** 渲染模板,并以字符串的形式取得渲染的结果。 */
    public String getText(String templateName, TemplateContext context) throws TemplateException, IOException {
        TemplateMatchResult result = findTemplate(templateName);
        TemplateEngine engine = assertNotNull(result.getEngine(), "templateEngine");

        return engine.getText(result.getTemplateName(), context);
    }

    /** 渲染模板,并将渲染的结果送到字节输出流中。 */
    public void writeTo(String templateName, TemplateContext context, OutputStream ostream) throws TemplateException,
                                                                                                   IOException {
        TemplateMatchResult result = findTemplate(templateName);
        TemplateEngine engine = assertNotNull(result.getEngine(), "templateEngine");

        engine.writeTo(result.getTemplateName(), context, ostream);
    }

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

        engine.writeTo(result.getTemplateName(), context, writer);
    }

    /** 查找指定名称的模板。 */
    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);
    }
}
TOP

Related Classes of com.alibaba.citrus.service.template.impl.TemplateServiceImpl

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.