diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java index 955a8e2a8..ab848e895 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/ajax/VitroAjaxController.java @@ -17,7 +17,7 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import freemarker.template.Configuration; import freemarker.template.Template; @@ -73,8 +73,8 @@ public abstract class VitroAjaxController extends HttpServlet { * Process data through a Freemarker template and output the result. */ protected void writeTemplate(String templateName, Map map, - VitroRequest vreq, HttpServletResponse response) { - Configuration config = FreemarkerConfigurationLoader.getConfig(vreq); + HttpServletRequest req, HttpServletResponse response) { + Configuration config = FreemarkerConfiguration.getConfig(req); try { Template template = config.getTemplate(templateName); PrintWriter out = response.getWriter(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java index d71dd7366..e01b14cd9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java @@ -61,6 +61,8 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet { return get(templateName, root, request); } + // JB Because this is pretending to be a servlet, but the init method has not been called, providing the context. + // Do that in the constructor, and we should be fine. VIVO-251 // RY We need the servlet context in getConfig(). For some reason using the method inherited from // GenericServlet bombs. @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java deleted file mode 100644 index b358b87b6..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java +++ /dev/null @@ -1,379 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.controller.freemarker; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; -import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; -import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; -import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants; -import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel; -import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter; -import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils; -import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective; -import edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective; -import edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective; -import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod; -import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod; -import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod; -import freemarker.cache.ClassTemplateLoader; -import freemarker.cache.FileTemplateLoader; -import freemarker.cache.MultiTemplateLoader; -import freemarker.cache.TemplateLoader; -import freemarker.core.Environment; -import freemarker.ext.beans.BeansWrapper; -import freemarker.template.Configuration; -import freemarker.template.DefaultObjectWrapper; -import freemarker.template.ObjectWrapper; -import freemarker.template.Template; -import freemarker.template.TemplateException; -import freemarker.template.TemplateModelException; -import freemarker.template.utility.DeepUnwrap; - -public class FreemarkerConfiguration extends Configuration { - - private static final Log log = LogFactory.getLog(FreemarkerConfiguration.class); - - private static final String PROPERTY_DEVELOPER_DEFEAT_CACHE = "developer.defeatFreemarkerCache"; - private static final String PROPERTY_DEVELOPER_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters"; - - private final String themeDir; - private final ServletContext context; - private final ApplicationBean appBean; - private final ConfigurationProperties props; - - FreemarkerConfiguration(String themeDir, ApplicationBean appBean, ServletContext context) { - - this.themeDir = themeDir; - this.context = context; - this.appBean = appBean; - this.props = ConfigurationProperties.getBean(context); - - String flag = props.getProperty(PROPERTY_DEVELOPER_DEFEAT_CACHE, "false"); - if (Boolean.valueOf(flag.trim())) { - log.debug("Disabling Freemarker template caching in development build."); - setTemplateUpdateDelay(0); // no template caching in development - } else { - int delay = 60; - log.debug("Setting Freemarker template cache update delay to " + delay + "."); - setTemplateUpdateDelay(delay); // in seconds; Freemarker default is 5 - } - - // Specify how templates will see the data model. - // The Freemarker default wrapper exposes set methods and get methods that take - // arguments. We block exposure to these methods by default. - BeansWrapper wrapper = new DefaultObjectWrapper(); - wrapper.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY); - setObjectWrapper(wrapper); - - // Set some formatting defaults. These can be overridden at the template - // or environment (template-processing) level, or for an individual - // token by using built-ins. - setLocale(java.util.Locale.US); - - String dateFormat = "M/d/yyyy"; - setDateFormat(dateFormat); - String timeFormat = "h:mm a"; - setTimeFormat(timeFormat); - setDateTimeFormat(dateFormat + " " + timeFormat); - - //config.setNumberFormat("#,##0.##"); - - try { - setSetting("url_escaping_charset", "ISO-8859-1"); - } catch (TemplateException e) { - log.error("Error setting value for url_escaping_charset."); - } - - setTemplateLoader(createTemplateLoader()); - - setSharedVariables(); - - } - - /** - * These are values that are accessible to all - * templates loaded by the Configuration's TemplateLoader. They - * should be application- rather than request-specific. - */ - private void setSharedVariables() { - - Map sharedVariables = new HashMap(); - - sharedVariables.put("siteName", appBean.getApplicationName()); - sharedVariables.put("version", getRevisionInfo()); - sharedVariables.put("urls", getSiteUrls()); - sharedVariables.put("themeDir", themeDir); - sharedVariables.put("currentTheme", themeDir.substring(themeDir.lastIndexOf('/')+1)); - - sharedVariables.putAll(getDirectives()); - sharedVariables.putAll(getMethods()); - sharedVariables.put("siteTagline", appBean.getShortHand()); - - //Put in edit configuration constants - useful for freemarker templates/editing - sharedVariables.put("editConfigurationConstants", EditConfigurationConstants.exportConstants()); - - for ( Map.Entry variable : sharedVariables.entrySet() ) { - try { - setSharedVariable(variable.getKey(), variable.getValue()); - } catch (TemplateModelException e) { - log.error("Could not set shared variable '" + variable.getKey() + "' in Freemarker configuration"); - } - } - } - - private final Map getRevisionInfo() { - Map map = new HashMap(); - map.put("label", RevisionInfoBean.getBean(context) - .getReleaseLabel()); - map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo")); - return map; - } - - private final Map getSiteUrls() { - Map urls = new HashMap(); - - // Templates use this to construct urls. - urls.put("base", context.getContextPath()); - - urls.put("home", UrlBuilder.getHomeUrl()); - urls.put("about", UrlBuilder.getUrl(Route.ABOUT)); - urls.put("search", UrlBuilder.getUrl(Route.SEARCH)); - urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE)); - urls.put("login", UrlBuilder.getLoginUrl()); - urls.put("logout", UrlBuilder.getLogoutUrl()); - urls.put("siteAdmin", UrlBuilder.getUrl(Route.SITE_ADMIN)); - urls.put("themeImages", UrlBuilder.getUrl(themeDir + "/images")); - urls.put("images", UrlBuilder.getUrl("/images")); - urls.put("theme", UrlBuilder.getUrl(themeDir)); - urls.put("index", UrlBuilder.getUrl("/browse")); - - return urls; - } - - private static Map getDirectives() { - Map map = new HashMap(); - map.put("dump", new freemarker.ext.dump.DumpDirective()); - map.put("dumpAll", new freemarker.ext.dump.DumpAllDirective()); - map.put("help", new freemarker.ext.dump.HelpDirective()); - map.put("shortView", new IndividualShortViewDirective()); - map.put("url", new UrlDirective()); - map.put("widget", new WidgetDirective()); - - - return map; - } - - private static Map getMethods() { - Map map = new HashMap(); - map.put("profileUrl", new IndividualProfileUrlMethod()); - map.put("localName", new IndividualLocalNameMethod()); - map.put("placeholderImageUrl", new IndividualPlaceholderImageUrlMethod()); - map.put("i18n", new I18nMethodModel()); - return map; - } - - // Define template locations. Template loader will look first in the theme-specific - // location, then in the vitro location. - protected final TemplateLoader createTemplateLoader() { - - List loaders = new ArrayList(); - MultiTemplateLoader mtl = null; - try { - // Theme template loader - String themeTemplatePath = context.getRealPath(themeDir) + "/templates"; - File themeTemplateDir = new File(themeTemplatePath); - // Handle the case where there's no theme template directory gracefully - if (themeTemplateDir.exists()) { - FileTemplateLoader themeFtl = new FileTemplateLoader(themeTemplateDir); - loaders.add(themeFtl); - } - - // Vitro template loader - String vitroTemplatePath = context.getRealPath("/templates/freemarker"); - loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath))); - - loaders.add(new ClassTemplateLoader(getClass(), "")); - - TemplateLoader[] loaderArray = loaders.toArray(new TemplateLoader[loaders.size()]); - mtl = new MultiTemplateLoader(loaderArray); - - } catch (IOException e) { - log.error("Error creating template loaders"); - } - - // Add the ability to add delimiters to the templates, based on - // settings. - if (Boolean.valueOf(props.getProperty(PROPERTY_DEVELOPER_INSERT_DELIMITERS))) { - return new DelimitingTemplateLoader(mtl); - } else { - return mtl; - } - } - - /** - * Override getTemplate(), so we can apply DataGetters to all included - * templates. - * - * This won't work for top-level Templates, since the Environment hasn't - * been created yet. When TemplateProcessingHelper creates the Environment, - * it must call retrieveAndRunDataGetters() for the top-level Template. - */ - @Override - public Template getTemplate(String name, Locale locale, String encoding, - boolean parse) throws IOException { - Template template = super.getTemplate(name, locale, encoding, parse); - - if (template == null) { - log.debug("Template '" + name + "' not found for locale '" + locale + "'."); - return template; - } - - Environment env = getEnvironment(); - if (env == null) { - log.debug("Not fetching data getters for template '" + template.getName() + "'. No environment."); - return template; - } - - retrieveAndRunDataGetters(env, template.getName()); - return template; - } - - - /** - * Find the DataGetters for this template, and apply them to the Freemarker - * environment. - */ - public static void retrieveAndRunDataGetters(Environment env, String templateName) { - HttpServletRequest req = (HttpServletRequest) env.getCustomAttribute("request"); - VitroRequest vreq = new VitroRequest(req); - - if (dataGettersAlreadyApplied(env, templateName)) { - log.debug("DataGetters for '" + templateName+"' have already been applied"); - return; - } - - try { - List dgList = DataGetterUtils.getDataGettersForTemplate( - vreq, vreq.getDisplayModel(), templateName); - log.debug("Retrieved " + dgList.size() + " data getters for template '" + templateName + "'"); - - @SuppressWarnings("unchecked") - Map dataMap = (Map) DeepUnwrap.permissiveUnwrap(env.getDataModel()); - for (DataGetter dg : dgList) { - applyDataGetter(dg, env, dataMap); - } - } catch (Exception e) { - log.warn(e, e); - } - } - - /** - * Have the DataGetters for this template already been applied to this environment? - * If not, record that they are being applied now. - */ - @SuppressWarnings("unchecked") - private static boolean dataGettersAlreadyApplied(Environment env, String templateName) { - Set names; - Object o = env.getCustomAttribute("dataGettersApplied"); - if (o instanceof Set) { - names = (Set) o; - } else { - names = new HashSet(); - } - - boolean added = names.add(templateName); - if (added) { - env.setCustomAttribute("dataGettersApplied", names); - return false; - } else { - return true; - } - } - - /** - * Get the data from a DataGetter, and store it in global variables in the - * Freemarker environment. - */ - private static void applyDataGetter(DataGetter dg, Environment env, - Map dataMap) throws TemplateModelException { - Map moreData = dg.getData(dataMap); - ObjectWrapper wrapper = env.getObjectWrapper(); - if (moreData != null) { - for (String key : moreData.keySet()) { - Object value = moreData.get(key); - env.setGlobalVariable(key, wrapper.wrap(value)); - log.debug("Stored in environment: '" + key + "' = '" + value + "'"); - } - } - } - - // ---------------------------------------------------------------------- - // Request info and overrides - // ---------------------------------------------------------------------- - - private ThreadLocal reqInfo = new ThreadLocal<>(); - - void setRequestInfo(HttpServletRequest req) { - reqInfo.set(new FreemarkerRequestInfo(req)); - } - - @Override - public Object getCustomAttribute(String name) { - if ("request".equals(name)) { - return reqInfo.get().getRequest(); - } else { - return super.getCustomAttribute(name); - } - } - - @Override - public String[] getCustomAttributeNames() { - String[] nameArray = super.getCustomAttributeNames(); - Set nameSet = new HashSet(Arrays.asList(nameArray)); - nameSet.add("request"); - return nameSet.toArray(new String[nameSet.size()]); - } - - @Override - public Locale getLocale() { - return reqInfo.get().getLocale(); - } - - - - public static class FreemarkerRequestInfo { - private final HttpServletRequest req; - - public FreemarkerRequestInfo(HttpServletRequest req) { - this.req = req; - } - - public HttpServletRequest getRequest() { - return req; - } - - public Locale getLocale() { - return req.getLocale(); - } - } - -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java deleted file mode 100644 index 340686d19..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java +++ /dev/null @@ -1,66 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.controller.freemarker; - -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; - -public class FreemarkerConfigurationLoader { - private static final Log log = LogFactory - .getLog(FreemarkerConfigurationLoader.class); - - private static final Map themeToConfigMap = new HashMap(); - - public static FreemarkerConfiguration getConfig(VitroRequest vreq) { - String themeDir = getThemeDir(vreq.getAppBean()); - FreemarkerConfiguration config = getConfigForTheme(themeDir, vreq.getAppBean(), vreq.getSession().getServletContext()); - config.setRequestInfo(vreq); - return config; - } - - private static String getThemeDir(ApplicationBean appBean) { - if (appBean == null) { - log.error("Cannot get themeDir from null application bean"); - return null; - } - - String themeDir = appBean.getThemeDir(); - if (themeDir == null) { - log.error("themeDir is null"); - return null; - } - - return themeDir.replaceAll("/$", ""); - } - - /** - * The Configuration is theme-specific because: - * - * 1. The template loader is theme-specific, since it specifies a theme - * directory to load templates from. - * - * 2. Some shared variables are theme-specific. - */ - private static FreemarkerConfiguration getConfigForTheme(String themeDir, - ApplicationBean appBean, ServletContext context) { - synchronized (themeToConfigMap) { - if (themeToConfigMap.containsKey(themeDir)) { - return themeToConfigMap.get(themeDir); - } else { - FreemarkerConfiguration config = new FreemarkerConfiguration( - themeDir, appBean, context); - themeToConfigMap.put(themeDir, config); - return config; - } - } - } - -} \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index 3cf0faeb0..135cf29b2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -37,10 +37,12 @@ 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.email.FreemarkerEmailFactory; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; 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.menu.MainMenu; import freemarker.ext.beans.BeansWrapper; +import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; @@ -336,7 +338,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { private Map buildRequestUrls(VitroRequest vreq) { Map requestUrls = new HashMap(); - FreemarkerConfiguration config = FreemarkerConfigurationLoader.getConfig(vreq); + Configuration config = FreemarkerConfiguration.getConfig(vreq); TemplateModel urlModel = config.getSharedVariable("urls"); try { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java index 828b09555..08b89c33c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/TemplateProcessingHelper.java @@ -13,7 +13,8 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfigurationImpl; import freemarker.core.Environment; import freemarker.template.Configuration; import freemarker.template.Template; @@ -26,7 +27,7 @@ public class TemplateProcessingHelper { private Configuration config = null; public TemplateProcessingHelper(HttpServletRequest request, ServletContext context) { - this.config = FreemarkerConfigurationLoader.getConfig(new VitroRequest(request)); + this.config = FreemarkerConfiguration.getConfig(request); } public StringWriter processTemplate(String templateName, Map map) @@ -50,7 +51,8 @@ public class TemplateProcessingHelper { } // Apply any data-getters that are associated with this template. - FreemarkerConfiguration.retrieveAndRunDataGetters(env, template.getName()); + // TODO clean this up VIVO-249 + FreemarkerConfigurationImpl.retrieveAndRunDataGetters(env, template.getName()); // Now process it. env.process(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java index 5068e2b1b..a214814f7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/n3editing/VTwo/EditConfigurationUtils.java @@ -23,11 +23,11 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.VClass; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; import edu.cornell.mannlib.vitro.webapp.dao.ModelAccess; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.edit.n3editing.VTwo.fields.FieldVTwo; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import freemarker.template.Configuration; public class EditConfigurationUtils { @@ -272,7 +272,7 @@ public class EditConfigurationUtils { //Generate HTML for a specific field name given public static String generateHTMLForElement(VitroRequest vreq, String fieldName, EditConfigurationVTwo editConfig) { String html = ""; - Configuration fmConfig = FreemarkerConfigurationLoader.getConfig(vreq); + Configuration fmConfig = FreemarkerConfiguration.getConfig(vreq); FieldVTwo field = editConfig == null ? null : editConfig.getField(fieldName); MultiValueEditSubmission editSub = EditSubmissionUtils.getEditSubmissionFromSession(vreq.getSession(), editConfig); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java index 84f0c1fcd..3f9d3d852 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailFactory.java @@ -25,9 +25,9 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfiguration; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import freemarker.template.Configuration; /** * A factory that creates Freemarker-based email messages. @@ -59,8 +59,7 @@ public class FreemarkerEmailFactory { } FreemarkerEmailFactory factory = getFactory(vreq); - FreemarkerConfiguration fConfig = FreemarkerConfigurationLoader - .getConfig(vreq); + Configuration fConfig = FreemarkerConfiguration.getConfig(vreq); return new FreemarkerEmailMessage(vreq, fConfig, factory.getEmailSession(), factory.getReplyToAddress()); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java index 1b3cd9a53..710242dd9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java @@ -28,8 +28,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.web.directives.EmailDirective; +import freemarker.template.Configuration; import freemarker.template.TemplateException; /** @@ -49,7 +49,7 @@ public class FreemarkerEmailMessage { private final VitroRequest vreq; private final Session mailSession; - private final FreemarkerConfiguration config; + private final Configuration config; private final List recipients = new ArrayList(); private final InternetAddress replyToAddress; @@ -64,7 +64,7 @@ public class FreemarkerEmailMessage { /** * Package access - should only be created by the factory. */ - FreemarkerEmailMessage(VitroRequest vreq, FreemarkerConfiguration fConfig, + FreemarkerEmailMessage(VitroRequest vreq, Configuration fConfig, Session mailSession, InternetAddress replyToAddress) { this.vreq = vreq; this.mailSession = mailSession; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java new file mode 100644 index 000000000..fe7555d35 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfiguration.java @@ -0,0 +1,293 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.freemarker.config; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; +import edu.cornell.mannlib.vitro.webapp.config.RevisionInfoBean; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.DelimitingTemplateLoader; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FlatteningTemplateLoader; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfigurationConstants; +import edu.cornell.mannlib.vitro.webapp.i18n.freemarker.I18nMethodModel; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; +import edu.cornell.mannlib.vitro.webapp.web.directives.IndividualShortViewDirective; +import edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective; +import edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective; +import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod; +import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualPlaceholderImageUrlMethod; +import edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod; +import freemarker.cache.ClassTemplateLoader; +import freemarker.cache.FileTemplateLoader; +import freemarker.cache.MultiTemplateLoader; +import freemarker.cache.TemplateLoader; +import freemarker.ext.beans.BeansWrapper; +import freemarker.template.Configuration; +import freemarker.template.DefaultObjectWrapper; +import freemarker.template.TemplateException; +import freemarker.template.TemplateModelException; + +/** + * Access point for a singleton Configuration instance. + * + * The instance is created at system startup, so we can fail early if there are + * any problems. + * + * The Configuration is slightly extended to hold request-based information in a + * ThreadLocal. The net result is although there is only one configuration (and + * hence only one template cache), each request gets a customization with its + * own locale, etc. + * + * Each time a request asks for the configuration, check to see whether the + * cache is still valid, and whether the theme has changed (needs a new + * TemplateLoader). Store the request info to the ThreadLocal. + */ +public abstract class FreemarkerConfiguration { + private static final Log log = LogFactory + .getLog(FreemarkerConfiguration.class); + + private static final String PROPERTY_DEFEAT_CACHE = "developer.defeatFreemarkerCache"; + private static final String PROPERTY_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters"; + + private static volatile FreemarkerConfigurationImpl instance; + private static volatile String previousThemeDir; + + public static Configuration getConfig(HttpServletRequest req) { + confirmInstanceIsSet(); + + synchronized (instance) { + clearTemplateCacheIfRequested(req); + keepTemplateLoaderCurrentWithThemeDirectory(req); + setThreadLocalsForRequest(req); + return instance; + } + } + + private static void confirmInstanceIsSet() { + if (instance == null) { + throw new IllegalStateException( + "VitroFreemarkerConfiguration has not been set."); + } + } + + private static void clearTemplateCacheIfRequested(HttpServletRequest req) { + if (isTemplateCacheInvalid(req)) { + instance.clearTemplateCache(); + } + } + + private static boolean isTemplateCacheInvalid(HttpServletRequest req) { + ConfigurationProperties props = ConfigurationProperties.getBean(req); + + // If the developer doesn't want the cache, it's invalid. + if (Boolean.valueOf(props.getProperty(PROPERTY_DEFEAT_CACHE))) { + return true; + } + + return false; + } + + /** + * Keep track of the theme directory. If it changes, create an appropriate + * new TemplateLoader. + * + * Note that setting a new TemplateLoader on the context Configuration also + * creates a new, empty TemplateCache. + */ + private static void keepTemplateLoaderCurrentWithThemeDirectory( + HttpServletRequest req) { + String themeDir = getThemeDirectory(req); + if (hasThemeDirectoryChanged(themeDir)) { + TemplateLoader tl = createTemplateLoader(req, themeDir); + instance.setTemplateLoader(tl); + } + } + + private static String getThemeDirectory(HttpServletRequest req) { + return new VitroRequest(req).getAppBean().getThemeDir(); + } + + private static boolean hasThemeDirectoryChanged(String themeDir) { + synchronized (instance) { + if (StringUtils.equals(themeDir, previousThemeDir)) { + return false; + } else { + previousThemeDir = themeDir; + return true; + } + } + } + + private static TemplateLoader createTemplateLoader(HttpServletRequest req, + String themeDir) { + ServletContext ctx = req.getSession().getServletContext(); + ConfigurationProperties props = ConfigurationProperties.getBean(ctx); + + List loaders = new ArrayList(); + + // Theme template loader + String themeTemplatePath = ctx.getRealPath(themeDir) + "/templates"; + File themeTemplateDir = new File(themeTemplatePath); + // A theme need not contain a template directory. + if (themeTemplateDir.exists()) { + try { + FileTemplateLoader themeFtl = new FileTemplateLoader( + themeTemplateDir); + loaders.add(themeFtl); + } catch (IOException e) { + log.error("Error creating theme template loader", e); + } + } + + // Vitro template loader + String vitroTemplatePath = ctx.getRealPath("/templates/freemarker"); + loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath))); + + // TODO VIVO-243 Why is this here? + loaders.add(new ClassTemplateLoader(FreemarkerConfiguration.class, "")); + + TemplateLoader[] loaderArray = loaders + .toArray(new TemplateLoader[loaders.size()]); + MultiTemplateLoader mtl = new MultiTemplateLoader(loaderArray); + + // If requested, add delimiters to the templates. + if (Boolean.valueOf(props.getProperty(PROPERTY_INSERT_DELIMITERS))) { + return new DelimitingTemplateLoader(mtl); + } else { + return mtl; + } + } + + private static void setThreadLocalsForRequest(HttpServletRequest req) { + instance.setRequestInfo(req); + } + + // ---------------------------------------------------------------------- + // Setup class + // ---------------------------------------------------------------------- + + public static class Setup implements ServletContextListener { + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + StartupStatus ss = StartupStatus.getBean(ctx); + try { + instance = createConfiguration(ctx); + ss.info(this, "Initialized the Freemarker configuration."); + } catch (Exception e) { + ss.fatal(this, + "Failed to initialize the Freemarker configuration.", e); + } + } + + private FreemarkerConfigurationImpl createConfiguration( + ServletContext ctx) throws TemplateModelException { + FreemarkerConfigurationImpl c = new FreemarkerConfigurationImpl(); + + setMiscellaneousProperties(c); + setSharedVariables(c, ctx); + addDirectives(c); + addMethods(c); + + return c; + } + + private void setMiscellaneousProperties(FreemarkerConfigurationImpl c) { + /* + * Lengthen the cache time. + */ + c.setTemplateUpdateDelay(60); // increase from the 5-second default + + /* + * On most template models, hide the getters and setters that take + * arguments. + */ + BeansWrapper wrapper = new DefaultObjectWrapper(); + wrapper.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY); + c.setObjectWrapper(wrapper); + + /* + * Set a default Locale, but expect it to be overridden by the + * request. + */ + c.setLocale(java.util.Locale.US); + + /* + * This is how we like our date and time strings to look. + */ + String dateFormat = "M/d/yyyy"; + c.setDateFormat(dateFormat); + String timeFormat = "h:mm a"; + c.setTimeFormat(timeFormat); + c.setDateTimeFormat(dateFormat + " " + timeFormat); + + /* + * What character set is used when escaping special characters in a + * URL? + */ + try { + c.setSetting("url_escaping_charset", "ISO-8859-1"); + } catch (TemplateException e) { + log.error("Error setting value for url_escaping_charset."); + } + } + + private void setSharedVariables(FreemarkerConfigurationImpl c, + ServletContext ctx) throws TemplateModelException { + c.setSharedVariable("version", getRevisionInfo(ctx)); + + /* + * Put in edit configuration constants - useful for freemarker + * templates/editing + */ + c.setSharedVariable("editConfigurationConstants", + EditConfigurationConstants.exportConstants()); + } + + private void addDirectives(FreemarkerConfigurationImpl c) { + c.setSharedVariable("dump", new freemarker.ext.dump.DumpDirective()); + c.setSharedVariable("dumpAll", + new freemarker.ext.dump.DumpAllDirective()); + c.setSharedVariable("help", new freemarker.ext.dump.HelpDirective()); + c.setSharedVariable("shortView", new IndividualShortViewDirective()); + c.setSharedVariable("url", new UrlDirective()); + c.setSharedVariable("widget", new WidgetDirective()); + } + + private void addMethods(FreemarkerConfigurationImpl c) { + c.setSharedVariable("profileUrl", new IndividualProfileUrlMethod()); + c.setSharedVariable("localName", new IndividualLocalNameMethod()); + c.setSharedVariable("placeholderImageUrl", + new IndividualPlaceholderImageUrlMethod()); + c.setSharedVariable("i18n", new I18nMethodModel()); + } + + private Map getRevisionInfo(ServletContext ctx) { + Map map = new HashMap(); + map.put("label", RevisionInfoBean.getBean(ctx).getReleaseLabel()); + map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo")); + return map; + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + instance = null; + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java new file mode 100644 index 000000000..b4318c97f --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/freemarker/config/FreemarkerConfigurationImpl.java @@ -0,0 +1,309 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.freemarker.config; + +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; +import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter; +import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetterUtils; +import freemarker.core.Environment; +import freemarker.template.Configuration; +import freemarker.template.ObjectWrapper; +import freemarker.template.SimpleScalar; +import freemarker.template.Template; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; +import freemarker.template.utility.DeepUnwrap; + +/** + * Extend the Freemarker Configuration class to include some information that is + * particular to the current request. + * + * Takes advantage of the fact that each servlet request runs in a separate + * thread. Stores the request-based information in a ThreadLocal. Override any + * methods that should return that information instead of (or in addition to) + * the common info. + * + * Only the getters are overridden, not the setters. So if you call + * setAllSharedVariables(), for example, it will have no effect on the + * request-based information. + */ +public class FreemarkerConfigurationImpl extends Configuration { + private static final Log log = LogFactory + .getLog(FreemarkerConfigurationImpl.class); + + private final ThreadLocal rbiRef = new ThreadLocal<>(); + + void setRequestInfo(HttpServletRequest req) { + rbiRef.set(new RequestBasedInformation(req, this)); + } + + @Override + public Object getCustomAttribute(String name) { + Map attribs = rbiRef.get().getCustomAttributes(); + if (attribs.containsKey(name)) { + return attribs.get(name); + } else { + return super.getCustomAttribute(name); + } + } + + @Override + public String[] getCustomAttributeNames() { + Set rbiNames = rbiRef.get().getCustomAttributes().keySet(); + return joinNames(rbiNames, super.getCustomAttributeNames()); + } + + @Override + public TemplateModel getSharedVariable(String name) { + Map vars = rbiRef.get().getSharedVariables(); + if (vars.containsKey(name)) { + return vars.get(name); + } else { + return super.getSharedVariable(name); + } + } + + @Override + public Set getSharedVariableNames() { + Set rbiNames = rbiRef.get().getSharedVariables().keySet(); + + @SuppressWarnings("unchecked") + Set superNames = super.getSharedVariableNames(); + + Set allNames = new HashSet<>(superNames); + allNames.addAll(rbiNames); + return allNames; + } + + @Override + public Locale getLocale() { + return rbiRef.get().getReq().getLocale(); + } + + private String[] joinNames(Set nameSet, String[] nameArray) { + Set allNames = new HashSet<>(nameSet); + for (String n : nameArray) { + allNames.add(n); + } + return (String[]) allNames.toArray(); + } + + // ---------------------------------------------------------------------- + // Apply DataGetters to templates when loading. + // + // TODO Clean this up VIVO-249 + // ---------------------------------------------------------------------- + + /** + * Override getTemplate(), so we can apply DataGetters to all included + * templates. + * + * This won't work for top-level Templates, since the Environment hasn't + * been created yet. When TemplateProcessingHelper creates the Environment, + * it must call retrieveAndRunDataGetters() for the top-level Template. + */ + @Override + public Template getTemplate(String name, Locale locale, String encoding, + boolean parse) throws IOException { + Template template = super.getTemplate(name, locale, encoding, parse); + + if (template == null) { + log.debug("Template '" + name + "' not found for locale '" + locale + + "'."); + return template; + } + + Environment env = getEnvironment(); + if (env == null) { + log.debug("Not fetching data getters for template '" + + template.getName() + "'. No environment."); + return template; + } + + retrieveAndRunDataGetters(env, template.getName()); + return template; + } + + /** + * Find the DataGetters for this template, and apply them to the Freemarker + * environment. + */ + public static void retrieveAndRunDataGetters(Environment env, + String templateName) { + HttpServletRequest req = (HttpServletRequest) env + .getCustomAttribute("request"); + VitroRequest vreq = new VitroRequest(req); + + if (dataGettersAlreadyApplied(env, templateName)) { + log.debug("DataGetters for '" + templateName + + "' have already been applied"); + return; + } + + try { + List dgList = DataGetterUtils + .getDataGettersForTemplate(vreq, vreq.getDisplayModel(), + templateName); + log.debug("Retrieved " + dgList.size() + + " data getters for template '" + templateName + "'"); + + @SuppressWarnings("unchecked") + Map dataMap = (Map) DeepUnwrap + .permissiveUnwrap(env.getDataModel()); + for (DataGetter dg : dgList) { + applyDataGetter(dg, env, dataMap); + } + } catch (Exception e) { + log.warn(e, e); + } + } + + /** + * Have the DataGetters for this template already been applied to this + * environment? If not, record that they are being applied now. + */ + @SuppressWarnings("unchecked") + private static boolean dataGettersAlreadyApplied(Environment env, + String templateName) { + Set names; + Object o = env.getCustomAttribute("dataGettersApplied"); + if (o instanceof Set) { + names = (Set) o; + } else { + names = new HashSet(); + } + + boolean added = names.add(templateName); + if (added) { + env.setCustomAttribute("dataGettersApplied", names); + return false; + } else { + return true; + } + } + + /** + * Get the data from a DataGetter, and store it in global variables in the + * Freemarker environment. + */ + private static void applyDataGetter(DataGetter dg, Environment env, + Map dataMap) throws TemplateModelException { + Map moreData = dg.getData(dataMap); + ObjectWrapper wrapper = env.getObjectWrapper(); + if (moreData != null) { + for (String key : moreData.keySet()) { + Object value = moreData.get(key); + env.setGlobalVariable(key, wrapper.wrap(value)); + log.debug("Stored in environment: '" + key + "' = '" + value + + "'"); + } + } + } + + // ---------------------------------------------------------------------- + // Helper class + // ---------------------------------------------------------------------- + + /** + * Holds the request-based information. Currently, it's shared variables, a + * custom attribute, and the locale. In the future, it could be more. + */ + private static class RequestBasedInformation { + private final HttpServletRequest req; + private final Configuration c; + private final Map customAttributes = new HashMap<>(); + private final Map sharedVariables = new HashMap<>(); + + public RequestBasedInformation(HttpServletRequest req, Configuration c) { + this.req = req; + this.c = c; + + setSharedVariables(req); + setCustomAttributes(req); + } + + public HttpServletRequest getReq() { + return req; + } + + public Map getCustomAttributes() { + return customAttributes; + } + + public Map getSharedVariables() { + return sharedVariables; + } + + private void setSharedVariables(HttpServletRequest req) { + ServletContext ctx = req.getSession().getServletContext(); + VitroRequest vreq = new VitroRequest(req); + ApplicationBean appBean = vreq.getAppBean(); + String siteName = appBean.getApplicationName(); + String tagLine = appBean.getShortHand(); + String themeDir = appBean.getThemeDir().replaceAll("/$", ""); + String currentTheme = themeDir + .substring(themeDir.lastIndexOf('/') + 1); + Map siteUrls = getSiteUrls(ctx, themeDir); + + sharedVariables.put("siteName", wrap(siteName)); + sharedVariables.put("themeDir", wrap(themeDir)); + sharedVariables.put("currentTheme", wrap(currentTheme)); + sharedVariables.put("siteTagline", wrap(tagLine)); + sharedVariables.put("urls", wrap(siteUrls)); + } + + private Map getSiteUrls(ServletContext ctx, + String themeDir) { + Map urls = new HashMap(); + + // Templates use this to construct urls. + urls.put("base", ctx.getContextPath()); + urls.put("home", UrlBuilder.getHomeUrl()); + urls.put("about", UrlBuilder.getUrl(Route.ABOUT)); + urls.put("search", UrlBuilder.getUrl(Route.SEARCH)); + urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE)); + urls.put("login", UrlBuilder.getLoginUrl()); + urls.put("logout", UrlBuilder.getLogoutUrl()); + urls.put("siteAdmin", UrlBuilder.getUrl(Route.SITE_ADMIN)); + + urls.put("themeImages", UrlBuilder.getUrl(themeDir + "/images")); + urls.put("images", UrlBuilder.getUrl("/images")); + urls.put("theme", UrlBuilder.getUrl(themeDir)); + urls.put("index", UrlBuilder.getUrl("/browse")); + + return urls; + } + + private TemplateModel wrap(Object o) { + try { + return c.getObjectWrapper().wrap(o); + } catch (TemplateModelException e) { + log.error("Failed to wrap this " + + "for the Freemarker configuration: " + o, e); + return new SimpleScalar(String.valueOf(o)); + } + } + + private void setCustomAttributes(HttpServletRequest req) { + customAttributes.put("request", req); + } + + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java index 2f53a8459..b6ccfd536 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/services/freemarker/FreemarkerProcessingServiceImpl.java @@ -12,8 +12,7 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils; import freemarker.core.ParseException; import freemarker.template.Configuration; @@ -51,8 +50,7 @@ public class FreemarkerProcessingServiceImpl implements throws TemplateProcessingException { Template template = null; try { - Configuration config = FreemarkerConfigurationLoader - .getConfig(new VitroRequest(req)); + Configuration config = FreemarkerConfiguration.getConfig(req); template = config.getTemplate(templateName); } catch (ParseException e) { log.warn("Failed to parse the template at '" + templateName + "'" diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java index f5036463c..b70c24818 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/DataPropertyTemplateModel.java @@ -5,8 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; @@ -21,13 +19,12 @@ import edu.cornell.mannlib.vitro.webapp.beans.DataProperty; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; -import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.DataPropertyListConfig; import freemarker.cache.TemplateLoader; @@ -136,7 +133,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel { } protected TemplateLoader getFreemarkerTemplateLoader() { - return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader(); + return FreemarkerConfiguration.getConfig(vreq).getTemplateLoader(); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java index 49e36d284..701ad0320 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java @@ -22,12 +22,12 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty; import edu.cornell.mannlib.vitro.webapp.beans.Property; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; -import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.Route; import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.InvalidConfigurationException; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.PropertyListConfig; import freemarker.cache.TemplateLoader; @@ -152,7 +152,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel * This will do for now. */ protected TemplateLoader getFreemarkerTemplateLoader() { - return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader(); + return FreemarkerConfiguration.getConfig(vreq).getTemplateLoader(); } protected List> getStatementData() { diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index d7e47e9d9..7f83a702a 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -65,6 +65,7 @@ edu.cornell.mannlib.vitro.webapp.i18n.selection.LocaleSelectionSetup edu.cornell.mannlib.vitro.webapp.search.solr.SolrSetup edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerSetup +edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration$Setup # On shutdown, this will kill the background thread started by Apache Commons File Upload org.apache.commons.fileupload.servlet.FileCleanerCleanup