From acc7495fe949e22350cf0ebbe6b6c5deadf8fdd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Gielen?= Date: Mon, 30 Jul 2007 07:05:55 +0000 Subject: [PATCH] WW-1661: Backporting Freemarker template caching to 2.0.x tree git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/branches/STRUTS_2_0_X@560881 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/struts2/StrutsConstants.java | 3 + .../template/FreemarkerTemplateEngine.java | 85 ++++++++++++++++--- .../struts2/config/BeanSelectionProvider.java | 1 + .../org/apache/struts2/default.properties | 4 + 4 files changed, 79 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index ca0948653..41c766528 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -76,6 +76,9 @@ public final class StrutsConstants { /** The org.apache.struts2.views.freemarker.FreemarkerManager implementation class */ public static final String STRUTS_FREEMARKER_MANAGER_CLASSNAME = "struts.freemarker.manager.classname"; + /** Cache Freemarker templates */ + public static final String STRUTS_FREEMARKER_TEMPLATES_CACHE = "struts.freemarker.templatesCache"; + /** org.apache.struts2.views.velocity.VelocityManager implementation class */ public static final String STRUTS_VELOCITY_MANAGER_CLASSNAME = "struts.velocity.manager.classname"; diff --git a/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java b/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java index 6a3554557..5f52b72ab 100644 --- a/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java +++ b/core/src/main/java/org/apache/struts2/components/template/FreemarkerTemplateEngine.java @@ -22,9 +22,7 @@ package org.apache.struts2.components.template; import java.io.IOException; import java.io.Writer; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -33,6 +31,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsConstants; import org.apache.struts2.views.freemarker.FreemarkerManager; import com.opensymphony.xwork2.inject.Inject; @@ -41,8 +40,7 @@ import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.util.ValueStack; -import freemarker.template.Configuration; -import freemarker.template.SimpleHash; +import freemarker.template.*; /** * Freemarker based template engine. @@ -51,6 +49,10 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine { static Class bodyContent = null; private FreemarkerManager freemarkerManager; + private final HashMap templates = new HashMap(); + private final HashSet missingTemplates = new HashSet(); + private boolean freemarkerCaching = false; + static { try { bodyContent = ClassLoaderUtil.loadClass("javax.servlet.jsp.tagext.BodyContent", @@ -88,16 +90,35 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine { freemarker.template.Template template = null; String templateName = null; Exception exception = null; - for (Iterator iterator = templates.iterator(); iterator.hasNext();) { - Template t = (Template) iterator.next(); + for (Object template1 : templates) { + Template t = (Template) template1; templateName = getFinalTemplateName(t); - try { - // try to load, and if it works, stop at the first one - template = config.getTemplate(templateName); - break; - } catch (IOException e) { - if (exception == null) { - exception = e; + if (freemarkerCaching) { + if (!isTemplateMissing(templateName)) { + try { + template = findInCache(templateName); // look in cache first + if (template == null) { + // try to load, and if it works, stop at the first one + template = config.getTemplate(templateName); + addToCache(templateName, template); + } + break; + } catch (IOException e) { + addToMissingTemplateCache(templateName); + if (exception == null) { + exception = e; + } + } + } + } else { + try { + // try to load, and if it works, stop at the first one + template = config.getTemplate(templateName); + break; + } catch (IOException e) { + if (exception == null) { + exception = e; + } } } } @@ -154,4 +175,40 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine { protected String getSuffix() { return "ftl"; } + + protected void addToMissingTemplateCache(String templateName) { + synchronized(missingTemplates) { + missingTemplates.add(templateName); + } + } + + protected boolean isTemplateMissing(String templateName) { + synchronized(missingTemplates) { + return missingTemplates.contains(templateName); + } + } + + protected void addToCache(String templateName, + freemarker.template.Template template) { + synchronized(templates) { + templates.put(templateName, template); + } + } + + protected freemarker.template.Template findInCache(String templateName) { + synchronized(templates) { + return templates.get(templateName); + } + } + + /** + * Enables or disables Struts caching of Freemarker templates. By default disabled. + * Set struts.freemarker.templatesCache=true to enable cache + * @param cacheTemplates "true" if the template engine should cache freemarker template + * internally + */ + @Inject(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE) + public void setCacheTemplates(String cacheTemplates) { + freemarkerCaching = "true".equals(cacheTemplates); + } } diff --git a/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java b/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java index c90c07f4a..f388bc4f6 100644 --- a/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java +++ b/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java @@ -163,6 +163,7 @@ public class BeanSelectionProvider implements ConfigurationProvider { if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) { props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true"); props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true"); + props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE, "false"); // Convert struts properties into ones that xwork expects props.setProperty("devMode", "true"); } else { diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties index 04af18cc9..0188b6bcb 100644 --- a/core/src/main/resources/org/apache/struts2/default.properties +++ b/core/src/main/resources/org/apache/struts2/default.properties @@ -164,6 +164,10 @@ struts.dispatcher.parametersWorkaround = false ### MUST extends off org.apache.struts2.views.freemarker.FreemarkerManager #struts.freemarker.manager.classname=org.apache.struts2.views.freemarker.FreemarkerManager +### Enables caching of FreeMarker templates +### Has the same effect as copying the templates under WEB_APP/templates +struts.freemarker.templatesCache=false + ### See the StrutsBeanWrapper javadocs for more information struts.freemarker.wrapper.altMap=true