/* * 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.freemarker.impl; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.CollectionUtil.*; import static com.alibaba.citrus.util.ObjectUtil.*; import static com.alibaba.citrus.util.StringUtil.*; import static freemarker.core.Configurable.OUTPUT_ENCODING_KEY; import static freemarker.core.Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY; import static freemarker.template.Configuration.*; import java.util.Map; import java.util.Set; import com.alibaba.citrus.service.freemarker.FreeMarkerConfiguration; import com.alibaba.citrus.service.freemarker.FreeMarkerPlugin; import com.alibaba.citrus.service.freemarker.support.DefaultBeansWrapper; import com.alibaba.citrus.service.template.TemplateException; import com.alibaba.citrus.util.ToStringBuilder.MapBuilder; import freemarker.cache.StrongCacheStorage; import freemarker.cache.TemplateLoader; import freemarker.template.Configuration; import org.slf4j.Logger; import org.springframework.core.io.ResourceLoader; /** * 代表一组freemarker engine的配置。 * * @author Michael Zhou */ public class FreeMarkerConfigurationImpl implements FreeMarkerConfiguration { private final Logger log; private final Configuration configuration = new Configuration(); private final Map<String, String> properties = createHashMap(); private boolean productionMode = true; private ResourceLoader loader; private TemplateLoader templateLoader; private String path; private String charset; private FreeMarkerPlugin[] plugins; /** 创建一个freemarker配置。 */ public FreeMarkerConfigurationImpl(Logger log) { this.log = assertNotNull(log, "log"); } /** 取得用于装载模板的loader。 */ public TemplateLoader getTemplateLoader() { return templateLoader; } /** 取得freemarker的配置。 */ public Configuration getConfiguration() { return configuration; } public Map<String, String> getProperties() { return properties; } public ResourceLoader getResourceLoader() { return loader; } /** 设置resource loader。 */ public void setResourceLoader(ResourceLoader loader) { this.loader = loader; } public boolean isProductionMode() { return productionMode; } /** 设置生产模式。默认为<code>true</code>。 */ public void setProductionMode(boolean productionMode) { this.productionMode = productionMode; } /** 设置搜索模板的根目录。默认为<code>/templates</code>。 */ public void setPath(String path) { this.path = trimToNull(path); } /** 设置模板的字符集编码。 */ public void setTemplateEncoding(String charset) { this.charset = trimToNull(charset); } /** 设置高级配置。 */ public void setAdvancedProperties(Map<String, String> configuration) { this.properties.clear(); this.properties.putAll(configuration); } /** 设置plugins。 */ public void setPlugins(FreeMarkerPlugin[] plugins) { this.plugins = plugins; } /** 初始化configuration。 */ public void init() { removeReservedProperties(); initProperties(); initPlugins(); initWrapper(); } /** 删除保留的properties,这些properties用户不能修改。 */ private void removeReservedProperties() { Set<String> keysToRemove = createHashSet(); keysToRemove.add(DEFAULT_ENCODING_KEY); keysToRemove.add(LOCALIZED_LOOKUP_KEY); // do removing for (String key : keysToRemove) { if (properties.containsKey(key)) { log.warn("Removed reserved property: {} = {}", key, properties.get(key)); properties.remove(key); } } } private void initProperties() { assertNotNull(loader, "resourceLoader"); // 模板字符集编码 if (charset == null) { charset = DEFAULT_CHARSET; } path = defaultIfNull(path, "/templates"); templateLoader = new SpringResourceLoaderAdapter(loader, path); configuration.setTemplateLoader(templateLoader); // 默认使用StrongCacheStorage setDefaultProperty(CACHE_STORAGE_KEY, StrongCacheStorage.class.getName()); // 异常处理器 setDefaultProperty(TEMPLATE_EXCEPTION_HANDLER_KEY, "rethrow"); // 其它默认选项 setDefaultProperty(DEFAULT_ENCODING_KEY, charset); setDefaultProperty(OUTPUT_ENCODING_KEY, DEFAULT_CHARSET); setDefaultProperty(LOCALIZED_LOOKUP_KEY, "false"); // 设置选项 for (Map.Entry<String, String> entry : properties.entrySet()) { String key = entry.getKey(); String value = trimToNull(entry.getValue()); if (value != null) { try { configuration.setSetting(key, value); } catch (freemarker.template.TemplateException e) { throw new TemplateException("invalid key and value: " + key + " = " + value, e); } } } } private void initPlugins() { if (plugins != null) { for (FreeMarkerPlugin plugin : plugins) { plugin.init(this); } } } private void initWrapper() { // 设置ObjectWrapper,使之支持TemplateContext对象 configuration.setObjectWrapper(new DefaultBeansWrapper(configuration.getObjectWrapper())); } /** 设置默认值。如果值已存在,则不覆盖。 */ private void setDefaultProperty(String key, String value) { if (properties.get(key) == null) { properties.put(key, value); } } @Override public String toString() { return new MapBuilder().setSortKeys(true).setPrintCount(true).appendAll(properties).toString(); } }