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

com.jfinal.template.Engine Maven / Gradle / Ivy

Go to download

the jfinal enjoy plugin for normal java program to use sql management function.

There is a newer version: 3.3.4
Show newest version
/**
 * Copyright (c) 2011-2017, James Zhan 詹波 ([email protected]).
 *
 * 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.jfinal.template;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.jfinal.template.expr.ast.MethodKit;
import com.jfinal.template.kit.HashKit;
import com.jfinal.template.kit.StrKit;
import com.jfinal.template.source.ISource;
import com.jfinal.template.source.ISourceFactory;
import com.jfinal.template.source.StringSource;
import com.jfinal.template.stat.Parser;
import com.jfinal.template.stat.ast.Stat;

/**
 * Engine
 * 
 * Example:
 * Engine.use().getTemplate(fileName).render(...);
 * Engine.use().getTemplate(fileName).renderToString(...);
 */
public class Engine {
	
	public static final String MAIN_ENGINE_NAME = "main";
	
	private static Engine MAIN_ENGINE;
	private static Map engineMap = new HashMap();
	
	// Create main engine
	static {
		MAIN_ENGINE = new Engine(MAIN_ENGINE_NAME);
		engineMap.put(MAIN_ENGINE_NAME, MAIN_ENGINE);
	}
	
	private String name;
	private boolean devMode = false;
	private EngineConfig config = new EngineConfig();
	private ISourceFactory sourceFactory = config.getSourceFactory();
	
	private Map templateCache = new HashMap();
	
	/**
	 * Create engine without management of JFinal 
	 */
	public Engine() {
		this.name = "NO_NAME";
	}
	
	/**
	 * Create engine by engineName without management of JFinal 
	 */
	public Engine(String engineName) {
		this.name = engineName;
	}
	
	/**
	 * Using the main Engine
	 */
	public static Engine use() {
		return MAIN_ENGINE;
	}
	
	/**
	 * Using the engine with engine name
	 */
	public static Engine use(String engineName) {
		return engineMap.get(engineName);
	}
	
	/**
	 * Create engine with engine name managed by JFinal
	 */
	public synchronized static Engine create(String engineName) {
		if (StrKit.isBlank(engineName)) {
			throw new IllegalArgumentException("Engine name can not be blank");
		}
		engineName = engineName.trim();
		if (engineMap.containsKey(engineName)) {
			throw new IllegalArgumentException("Engine already exists : " + engineName);
		}
		Engine newEngine = new Engine(engineName);
		engineMap.put(engineName, newEngine);
		return newEngine;
	}
	
	/**
	 * Remove engine with engine name managed by JFinal
	 */
	public synchronized static Engine remove(String engineName) {
		Engine removed = engineMap.remove(engineName);
		if (removed != null && MAIN_ENGINE_NAME.equals(removed.name)) {
			Engine.MAIN_ENGINE = null;
		}
		return removed;
	}
	
	/**
	 * Set main engine
	 */
	public synchronized static void setMainEngine(Engine engine) {
		if (engine == null) {
			throw new IllegalArgumentException("Engine can not be null");
		}
		engine.name = Engine.MAIN_ENGINE_NAME;
		engineMap.put(Engine.MAIN_ENGINE_NAME, engine);
		Engine.MAIN_ENGINE = engine;
	}
	
	/**
	 * Get template with file name
	 */
	public Template getTemplate(String fileName) {
		if (fileName.charAt(0) != '/') {
			char[] arr = new char[fileName.length() + 1];
			fileName.getChars(0, fileName.length(), arr, 1);
			arr[0] = '/';
			fileName = new String(arr);
		}
		
		Template template = templateCache.get(fileName);
		if (template == null) {
			template = buildTemplateBySourceFactory(fileName);
			templateCache.put(fileName, template);
		} else if (devMode) {
			if (template.isModified()) {
				template = buildTemplateBySourceFactory(fileName);
				templateCache.put(fileName, template);
			}
		}
		return template;
	}
	
	private Template buildTemplateBySourceFactory(String fileName) {
		// FileSource fileSource = new FileSource(config.getBaseTemplatePath(), fileName, config.getEncoding());
		ISource source = sourceFactory.getSource(config.getBaseTemplatePath(), fileName, config.getEncoding());
		Env env = new Env(config);
		Parser parser = new Parser(env, source.getContent(), fileName);
		if (devMode) {
			env.addSource(source);
		}
		Stat stat = parser.parse();
		Template template = new Template(env, stat);
		return template;
	}
	
	/**
	 * Get template by string content and do not cache the template
	 * 
	 * 重要:StringSource 中的 key = HashKit.md5(content),也即 key
	 *     与 content 有紧密的对应关系,当 content 发生变化时 key 值也相应变化
	 *     因此,原先 key 所对应的 Template 缓存对象已无法被获取,当 getTemplateByString(String)
	 *     的 String 参数的数量不确定时会引发内存泄漏
	 *     
	 *     当 getTemplateByString(String, boolean) 中的 String 参数的
	 *     数量可控并且确定时,才可对其使用缓存 
	 */
	public Template getTemplateByString(String content) {
		return getTemplateByString(content, false);
	}
	
	/**
	 * Get template by string content
	 * @param content 模板内容
	 * @param cache true 则缓存 Template,否则不缓存
	 */
	public Template getTemplateByString(String content, boolean cache) {
		if (!cache) {
			return buildTemplateBySource(new StringSource(content, cache));
		}
		
		String key = HashKit.md5(content);
		Template template = templateCache.get(key);
		if (template == null) {
			template = buildTemplateBySource(new StringSource(content, cache));
			templateCache.put(key, template);
		} else if (devMode) {
			if (template.isModified()) {
				template = buildTemplateBySource(new StringSource(content, cache));
				templateCache.put(key, template);
			}
		}
		return template;
	}
	
	/**
	 * Get template with implementation of ISource
	 */
	public Template getTemplate(ISource source) {
		String key = source.getKey();
		if (key == null) {	// key 为 null 则不缓存,详见 ISource.getKey() 注释
			return buildTemplateBySource(source);
		}
		
		Template template = templateCache.get(key);
		if (template == null) {
			template = buildTemplateBySource(source);
			templateCache.put(key, template);
		} else if (devMode) {
			if (template.isModified()) {
				template = buildTemplateBySource(source);
				templateCache.put(key, template);
			}
		}
		return template;
	}
	
	private Template buildTemplateBySource(ISource source) {
		Env env = new Env(config);
		Parser parser = new Parser(env, source.getContent(), null);
		if (devMode) {
			env.addSource(source);
		}
		Stat stat = parser.parse();
		Template template = new Template(env, stat);
		return template;
	}
	
	/**
	 * Add shared function with file
	 */
	public Engine addSharedFunction(String fileName) {
		config.addSharedFunction(fileName);
		return this;
	}
	
	/**
	 * Add shared function by ISource
	 */
	public Engine addSharedFunction(ISource source) {
		config.addSharedFunction(source);
		return this;
	}
	
	/**
	 * Add shared function with files
	 */
	public Engine addSharedFunction(String... fileNames) {
		config.addSharedFunction(fileNames);
		return this;
	}
	
	/**
	 * Add shared function by string content
	 */
	public Engine addSharedFunctionByString(String content) {
		config.addSharedFunctionByString(content);
		return this;
	}
	
	/**
	 * Add shared object
	 */
	public Engine addSharedObject(String name, Object object) {
		config.addSharedObject(name, object);
		return this;
	}
	
	/**
	 * Set output directive factory
	 */
	public Engine setOutputDirectiveFactory(IOutputDirectiveFactory outputDirectiveFactory) {
		config.setOutputDirectiveFactory(outputDirectiveFactory);
		return this;
	}
	
	/**
	 * Add directive
	 * 
	 * 示例:
	 * addDirective("now", NowDirective.class)
	 * 
*/ public Engine addDirective(String directiveName, Class directiveClass) { config.addDirective(directiveName, directiveClass); return this; } /** * 该方法已被 addDirective(String, Class) 所代替 */ @Deprecated public Engine addDirective(String directiveName, Directive directive) { return addDirective(directiveName, directive.getClass()); } /** * Remove directive */ public Engine removeDirective(String directiveName) { config.removeDirective(directiveName); return this; } /** * Add shared method from object */ public Engine addSharedMethod(Object sharedMethodFromObject) { config.addSharedMethod(sharedMethodFromObject); return this; } /** * Add shared method from class */ public Engine addSharedMethod(Class sharedMethodFromClass) { config.addSharedMethod(sharedMethodFromClass); return this; } /** * Add shared static method of Class */ public Engine addSharedStaticMethod(Class sharedStaticMethodFromClass) { config.addSharedStaticMethod(sharedStaticMethodFromClass); return this; } /** * Remove shared Method with method name */ public Engine removeSharedMethod(String methodName) { config.removeSharedMethod(methodName); return this; } /** * Remove shared Method of the Class */ public Engine removeSharedMethod(Class clazz) { config.removeSharedMethod(clazz); return this; } /** * Remove shared Method */ public Engine removeSharedMethod(Method method) { config.removeSharedMethod(method); return this; } /** * Remove template cache with template key */ public void removeTemplateCache(String templateKey) { templateCache.remove(templateKey); } /** * Remove all template cache */ public void removeAllTemplateCache() { templateCache.clear(); } public int getTemplateCacheSize() { return templateCache.size(); } public String getName() { return name; } public String toString() { return "Template Engine: " + name; } // Engine config below --------- public EngineConfig getEngineConfig() { return config; } /** * 设置 true 为开发模式,支持模板文件热加载 * 设置 false 为生产模式,不支持模板文件热加载,以达到更高的性能 */ public Engine setDevMode(boolean devMode) { this.devMode = devMode; this.config.setDevMode(devMode); if (this.devMode) { removeAllTemplateCache(); } return this; } public boolean getDevMode() { return devMode; } /** * 设置 ISourceFactory 用于为 engine 切换不同的 ISource 实现类 * ISource 用于从不同的来源加载模板内容 * *
	 * 配置为 ClassPathSourceFactory 时特别注意:
	 *    由于 JFinal 会在 configEngine(Engine me) 方法调用 “之前”,会默认调用一次如下方法:
	 *       me.setBaseTemplatePath(PathKit.getWebRootPath())
	 *    
	 *    而 ClassPathSourceFactory 在以上默认值下不能工作,所以需要通过如下方式清掉该值:
	 *       me.setBaseTemplatePath(null)
	 *    
	 *    或者配置具体要用的 baseTemplatePath 值,例如:
	 *       me.setBaseTemplatePath("view");
	 * 
*/ public Engine setSourceFactory(ISourceFactory sourceFactory) { this.config.setSourceFactory(sourceFactory); // 放第一行先进行参数验证 this.sourceFactory = sourceFactory; return this; } public ISourceFactory getSourceFactory() { return sourceFactory; } public Engine setBaseTemplatePath(String baseTemplatePath) { config.setBaseTemplatePath(baseTemplatePath); return this; } public String getBaseTemplatePath() { return config.getBaseTemplatePath(); } public Engine setDatePattern(String datePattern) { config.setDatePattern(datePattern); return this; } public String getDatePattern() { return config.getDatePattern(); } public Engine setEncoding(String encoding) { config.setEncoding(encoding); return this; } public String getEncoding() { return config.getEncoding(); } public Engine setWriterBufferSize(int bufferSize) { config.setWriterBufferSize(bufferSize); return this; } /** * Engine 独立设置为 devMode 可以方便模板文件在修改后立即生效, * 但如果在 devMode 之下并不希望对 addSharedFunction(...), * 添加的模板进行是否被修改的检测可以通过此方法设置 false 参进去 * * 注意:Engine 在生产环境下(devMode 为 false),该参数无效 */ public Engine setReloadModifiedSharedFunctionInDevMode(boolean reloadModifiedSharedFunctionInDevMode) { config.setReloadModifiedSharedFunctionInDevMode(reloadModifiedSharedFunctionInDevMode); return this; } public static void addExtensionMethod(Class targetClass, Object objectOfExtensionClass) { MethodKit.addExtensionMethod(targetClass, objectOfExtensionClass); } public static void addExtensionMethod(Class targetClass, Class extensionClass) { MethodKit.addExtensionMethod(targetClass, extensionClass); } public static void removeExtensionMethod(Class targetClass, Object objectOfExtensionClass) { MethodKit.removeExtensionMethod(targetClass, objectOfExtensionClass); } public static void removeExtensionMethod(Class targetClass, Class extensionClass) { MethodKit.removeExtensionMethod(targetClass, extensionClass); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy