Resolved WW-3467 - Improve performance for page rendering by refactoring freemarker cache

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@965050 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Lukasz Lenart
2010-07-17 10:10:46 +00:00
parent 1b1873bf26
commit ecf85f4d44
4 changed files with 21 additions and 95 deletions
@@ -82,9 +82,13 @@ 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 */
@Deprecated
/** Cache Freemarker templates, this cache is managed by struts2,instead of native freemarker cache,set STRUTS_FREEMARKER_MRU_MAX_STRONG_SIZE >0&&STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY>0*/
public static final String STRUTS_FREEMARKER_TEMPLATES_CACHE = "struts.freemarker.templatesCache";
/** Update freemarker templates cache in seconds*/
public static final String STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY = "struts.freemarker.templatesCache.updateDelay";
/** Cache model instances at BeanWrapper level */
public static final String STRUTS_FREEMARKER_BEANWRAPPER_CACHE = "struts.freemarker.beanwrapperCache";
@@ -23,16 +23,14 @@ package org.apache.struts2.components.template;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.Map;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.views.freemarker.FreemarkerManager;
import com.opensymphony.xwork2.ActionContext;
@@ -54,10 +52,6 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
static Class bodyContent = null;
protected FreemarkerManager freemarkerManager;
protected final Map<String, freemarker.template.Template> templates = new ConcurrentHashMap<String, freemarker.template.Template>();
protected final Set<String> missingTemplates = new CopyOnWriteArraySet<String>();
protected boolean freemarkerCaching = false;
static {
try {
bodyContent = ClassLoaderUtil.loadClass("javax.servlet.jsp.tagext.BodyContent",
@@ -97,24 +91,6 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
Exception exception = null;
for (Template t : templates) {
templateName = getFinalTemplateName(t);
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);
@@ -129,7 +105,6 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
exception = e;
}
}
}
}
if (template == null) {
@@ -189,39 +164,5 @@ public class FreemarkerTemplateEngine extends BaseTemplateEngine {
return "ftl";
}
protected void addToMissingTemplateCache(String templateName) {
missingTemplates.add(templateName);
}
protected boolean isTemplateMissing(String templateName) {
return missingTemplates.contains(templateName);
}
protected void addToCache(String templateName,
freemarker.template.Template template) {
templates.put(templateName, template);
}
protected freemarker.template.Template findInCache(String templateName) {
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);
}
/**
* Clear the templates and missing templates cache
*/
public void clearTemplatesCache() {
templates.clear();
missingTemplates.clear();
}
}
@@ -26,7 +26,6 @@ import java.util.StringTokenizer;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.components.UrlRenderer;
import org.apache.struts2.dispatcher.DefaultStaticContentLoader;
import org.apache.struts2.dispatcher.StaticContentLoader;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.multipart.MultiPartRequest;
@@ -222,6 +221,7 @@ public class BeanSelectionProvider implements ConfigurationProvider {
props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true");
props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true");
props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE, "false");
props.setProperty(StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY, "0");
// Convert struts properties into ones that xwork expects
props.setProperty("devMode", "true");
} else {
@@ -50,14 +50,12 @@ import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.cache.WebappTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.jsp.TaglibFactory;
import freemarker.ext.servlet.HttpRequestHashModel;
import freemarker.ext.servlet.HttpRequestParametersHashModel;
import freemarker.ext.servlet.HttpSessionHashModel;
import freemarker.ext.servlet.ServletContextHashModel;
import freemarker.template.*;
import freemarker.core.Configurable;
import freemarker.template.utility.StringUtil;
@@ -117,7 +115,6 @@ public class FreemarkerManager {
// Note these names start with dot, so they're essentially invisible from a freemarker script.
private static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
private static final String ATTR_REQUEST_PARAMETERS_MODEL = ".freemarker.RequestParameters";
private static final String ATTR_SESSION_MODEL = ".freemarker.Session";
private static final String ATTR_APPLICATION_MODEL = ".freemarker.Application";
private static final String ATTR_JSP_TAGLIBS_MODEL = ".freemarker.JspTaglibs";
@@ -169,6 +166,7 @@ public class FreemarkerManager {
protected boolean altMapWrapper;
protected boolean cacheBeanWrapper;
protected int mruMaxStrongSize;
protected String templateUpdateDelay;
protected Map<String,TagLibrary> tagLibraries;
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
@@ -191,6 +189,11 @@ public class FreemarkerManager {
mruMaxStrongSize = Integer.parseInt(size);
}
@Inject(value = StrutsConstants.STRUTS_FREEMARKER_TEMPLATES_CACHE_UPDATE_DELAY, required = false)
public void setTemplateUpdateDelay(String delay) {
templateUpdateDelay = delay;
}
@Inject
public void setContainer(Container container) {
Map<String,TagLibrary> map = new HashMap<String,TagLibrary>();
@@ -229,7 +232,7 @@ public class FreemarkerManager {
return contentType;
}
public synchronized freemarker.template.Configuration getConfiguration(ServletContext servletContext) {
public synchronized Configuration getConfiguration(ServletContext servletContext) {
if (config == null) {
try {
init(servletContext);
@@ -287,15 +290,17 @@ public class FreemarkerManager {
*
* @param servletContext
*/
protected freemarker.template.Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
freemarker.template.Configuration configuration = new freemarker.template.Configuration();
protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException {
Configuration configuration = new Configuration();
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
if (mruMaxStrongSize > 0) {
configuration.setSetting(freemarker.template.Configuration.CACHE_STORAGE_KEY, "strong:" + mruMaxStrongSize);
configuration.setSetting(Configuration.CACHE_STORAGE_KEY, "strong:" + mruMaxStrongSize);
}
if (templateUpdateDelay != null) {
configuration.setSetting(Configuration.TEMPLATE_UPDATE_DELAY_KEY, templateUpdateDelay);
}
if (encoding != null) {
configuration.setDefaultEncoding(encoding);
}
@@ -333,17 +338,8 @@ public class FreemarkerManager {
// Create hash model wrapper for session
HttpSession session = request.getSession(false);
HttpSessionHashModel sessionModel;
if (session != null) {
sessionModel = (HttpSessionHashModel) session.getAttribute(ATTR_SESSION_MODEL);
if (sessionModel == null) {
sessionModel = new HttpSessionHashModel(session, wrapper);
session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
}
model.put(KEY_SESSION, new HttpSessionHashModel(session, wrapper));
} else {
// no session means no attributes ???
// model.put(KEY_SESSION_MODEL, new SimpleHash());
}
// Create hash model wrapper for the request attributes
@@ -525,19 +521,4 @@ public class FreemarkerManager {
}
}
/**
* If the parameter "nocache" was set to true, generate a set of headers
* that will advise the HTTP client not to cache the returned page.
*/
private void setBrowserCachingPolicy(HttpServletResponse res) {
if (nocache) {
// HTTP/1.1 + IE extensions
res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, "
+ "post-check=0, pre-check=0");
// HTTP/1.0
res.setHeader("Pragma", "no-cache");
// Last resort for those that ignore all of the above
res.setHeader("Expires", EXPIRATION_DATE);
}
}
}