NIHVIVO-3547 Move the "stylesheets", "scripts", and "headscripts" variables from the FreemarkerConfiguration, where they are effectively singletons, to the data model map, where they are created for each separate request.

This commit is contained in:
j2blake 2012-01-13 16:50:03 +00:00
parent 70e3bd6503
commit 6bce20b84e
4 changed files with 26 additions and 57 deletions

View file

@ -36,7 +36,6 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet {
VitroRequest vreq = new VitroRequest(request); VitroRequest vreq = new VitroRequest(request);
FreemarkerConfiguration config = getConfig(vreq); FreemarkerConfiguration config = getConfig(vreq);
vreq.setAttribute("freemarkerConfig", config); vreq.setAttribute("freemarkerConfig", config);
config.resetRequestSpecificSharedVariables();
Map<String, Object> map = getPageTemplateValues(vreq); Map<String, Object> map = getPageTemplateValues(vreq);
request.setAttribute("ftl_head", getHead("head", map, config, vreq)); request.setAttribute("ftl_head", getHead("head", map, config, vreq));

View file

@ -5,14 +5,12 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -21,8 +19,6 @@ import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean; import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags.TagsWrapper;
import freemarker.cache.ClassTemplateLoader; import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.FileTemplateLoader; import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader; import freemarker.cache.MultiTemplateLoader;
@ -31,7 +27,6 @@ import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration; import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper; import freemarker.template.DefaultObjectWrapper;
import freemarker.template.TemplateException; import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelException;
public class FreemarkerConfiguration extends Configuration { public class FreemarkerConfiguration extends Configuration {
@ -42,9 +37,6 @@ public class FreemarkerConfiguration extends Configuration {
private final ServletContext context; private final ServletContext context;
private final ApplicationBean appBean; private final ApplicationBean appBean;
private final String appName; private final String appName;
private final Tags stylesheets;
private final Tags scripts;
private final Tags headScripts;
FreemarkerConfiguration(String themeDir, VitroRequest vreq, ServletContext context) { FreemarkerConfiguration(String themeDir, VitroRequest vreq, ServletContext context) {
@ -53,10 +45,6 @@ public class FreemarkerConfiguration extends Configuration {
this.appBean = vreq.getAppBean(); this.appBean = vreq.getAppBean();
this.appName = appBean.getApplicationName(); this.appName = appBean.getApplicationName();
this.stylesheets = new Tags();
this.scripts = new Tags();
this.headScripts = new Tags();
String buildEnv = ConfigurationProperties.getBean(context).getProperty("Environment.build"); String buildEnv = ConfigurationProperties.getBean(context).getProperty("Environment.build");
log.debug("Current build environment: " + buildEnv); log.debug("Current build environment: " + buildEnv);
if ("development".equals(buildEnv)) { // Set Environment.build = development in deploy.properties if ("development".equals(buildEnv)) { // Set Environment.build = development in deploy.properties
@ -100,25 +88,10 @@ public class FreemarkerConfiguration extends Configuration {
} }
/** Some template variables are shared so that they are accessible to
* all templates, but they are request-specific and so need to be
* reset at the beginning of a new request.
*
* This is public for now because it's accessed by propDelete.jsp.
* Once the property deletion is integrated into Freemarker and generated
* with a Freemarker page, the visibility can be reduced to package.
*/
public void resetRequestSpecificSharedVariables() {
stylesheets.reset();
scripts.reset();
headScripts.reset();
}
/** /**
* These are values that are accessible to all * These are values that are accessible to all
* templates loaded by the Configuration's TemplateLoader. They * templates loaded by the Configuration's TemplateLoader. They
* should be application- rather than request-specific, or else get * should be application- rather than request-specific.
* reset with a new request.
* @param VitroRequest vreq * @param VitroRequest vreq
*/ */
private void setSharedVariables(VitroRequest vreq) { private void setSharedVariables(VitroRequest vreq) {
@ -131,10 +104,6 @@ public class FreemarkerConfiguration extends Configuration {
sharedVariables.put("themeDir", themeDir); sharedVariables.put("themeDir", themeDir);
sharedVariables.put("currentTheme", themeDir.substring(themeDir.lastIndexOf('/')+1)); sharedVariables.put("currentTheme", themeDir.substring(themeDir.lastIndexOf('/')+1));
sharedVariables.put("stylesheets", wrapTagList(stylesheets));
sharedVariables.put("scripts", wrapTagList(scripts));
sharedVariables.put("headScripts", wrapTagList(headScripts));
sharedVariables.putAll(getDirectives()); sharedVariables.putAll(getDirectives());
sharedVariables.putAll(getMethods()); sharedVariables.putAll(getMethods());
sharedVariables.put("siteTagline", appBean.getShortHand()); sharedVariables.put("siteTagline", appBean.getShortHand());
@ -177,23 +146,6 @@ public class FreemarkerConfiguration extends Configuration {
return urls; return urls;
} }
/** Script and stylesheet lists are wrapped with a specialized BeansWrapper
* that exposes certain write methods, instead of the configuration's object wrapper,
* which doesn't. The templates can then add stylesheets and scripts to the lists
* by calling their add() methods.
* @param Tags tags
* @return TemplateModel
*/
private TemplateModel wrapTagList(Tags tags) {
try {
BeansWrapper wrapper = new TagsWrapper();
return wrapper.wrap(tags); // this is a StringModel
} catch (TemplateModelException e) {
log.error("Error creating Tags template model");
return null;
}
}
public static Map<String, Object> getDirectives() { public static Map<String, Object> getDirectives() {
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
map.put("dump", new freemarker.ext.dump.DumpDirective()); map.put("dump", new freemarker.ext.dump.DumpDirective());

View file

@ -37,6 +37,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Res
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.User;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.MainMenu; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.menu.MainMenu;
import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.BeansWrapper;
@ -101,7 +102,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
FreemarkerConfiguration config = getConfig(vreq); FreemarkerConfiguration config = getConfig(vreq);
vreq.setAttribute("freemarkerConfig", config); vreq.setAttribute("freemarkerConfig", config);
config.resetRequestSpecificSharedVariables();
responseValues = processRequest(vreq); responseValues = processRequest(vreq);
doResponse(vreq, response, responseValues); doResponse(vreq, response, responseValues);
@ -444,6 +444,12 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
map.put("url", new edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective()); map.put("url", new edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective());
map.put("widget", new edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective()); map.put("widget", new edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective());
// Add these accumulator objects. They will collect tags so the template can write them
// at the appropriate location.
map.put("stylesheets", new Tags().wrap());
map.put("scripts", new Tags().wrap());
map.put("headScripts", new Tags().wrap());
return map; return map;
} }

View file

@ -9,9 +9,9 @@ import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper;
import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision; import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;
public class Tags extends BaseTemplateModel { public class Tags extends BaseTemplateModel {
@ -27,10 +27,22 @@ public class Tags extends BaseTemplateModel {
this.tags = tags; this.tags = tags;
} }
public void reset() { public TemplateModel wrap() {
tags.clear(); try {
return new TagsWrapper().wrap(this);
} catch (TemplateModelException e) {
log.error("Error creating Tags template model");
return null;
}
} }
/** Script and stylesheet lists are wrapped with a specialized BeansWrapper
* that exposes certain write methods, instead of the configuration's object wrapper,
* which doesn't. The templates can then add stylesheets and scripts to the lists
* by calling their add() methods.
* @param Tags tags
* @return TemplateModel
*/
static public class TagsWrapper extends BeansWrapper { static public class TagsWrapper extends BeansWrapper {
public TagsWrapper() { public TagsWrapper() {
@ -67,7 +79,7 @@ public class Tags extends BaseTemplateModel {
} }
public String list() { public String list() {
return StringUtils.join(tags, ""); return StringUtils.join(tags, "\n");
} }