VIVO-246 Re-implement the FreemarkerConfiguration
The Configuration must contain mutable information like the theme directory and the TemplateLoader. It must also be request-specific so it can have the correct Locale for language support. But we should only have one instance, so there is only one TemplateCache (alternatively, one TemplateCache per theme). Previously, this was addressed by intercepting the Template processing and adding the request-based info to the Environment. However, this interception code needed to appear each time a Template was processed. This was sometimes overlooked, and at best introduced a bunch of duplicated code. Instead, I extended the freemarker Configuration class to include a ThreadLocal that holds request-specific information.
This commit is contained in:
parent
98bb7236d1
commit
3f061da006
15 changed files with 630 additions and 472 deletions
|
@ -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.policy.PolicyHelper;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
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.Configuration;
|
||||||
import freemarker.template.Template;
|
import freemarker.template.Template;
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ public abstract class VitroAjaxController extends HttpServlet {
|
||||||
* Process data through a Freemarker template and output the result.
|
* Process data through a Freemarker template and output the result.
|
||||||
*/
|
*/
|
||||||
protected void writeTemplate(String templateName, Map<String, Object> map,
|
protected void writeTemplate(String templateName, Map<String, Object> map,
|
||||||
VitroRequest vreq, HttpServletResponse response) {
|
HttpServletRequest req, HttpServletResponse response) {
|
||||||
Configuration config = FreemarkerConfigurationLoader.getConfig(vreq);
|
Configuration config = FreemarkerConfiguration.getConfig(req);
|
||||||
try {
|
try {
|
||||||
Template template = config.getTemplate(templateName);
|
Template template = config.getTemplate(templateName);
|
||||||
PrintWriter out = response.getWriter();
|
PrintWriter out = response.getWriter();
|
||||||
|
|
|
@ -61,6 +61,8 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet {
|
||||||
return get(templateName, root, request);
|
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
|
// RY We need the servlet context in getConfig(). For some reason using the method inherited from
|
||||||
// GenericServlet bombs.
|
// GenericServlet bombs.
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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<String, Object> sharedVariables = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
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<String, Object> 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<String, Object> getRevisionInfo() {
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
map.put("label", RevisionInfoBean.getBean(context)
|
|
||||||
.getReleaseLabel());
|
|
||||||
map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo"));
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<String, String> getSiteUrls() {
|
|
||||||
Map<String, String> urls = new HashMap<String, String>();
|
|
||||||
|
|
||||||
// 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<String, Object> getDirectives() {
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
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<String, Object> getMethods() {
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
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<TemplateLoader> loaders = new ArrayList<TemplateLoader>();
|
|
||||||
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<DataGetter> dgList = DataGetterUtils.getDataGettersForTemplate(
|
|
||||||
vreq, vreq.getDisplayModel(), templateName);
|
|
||||||
log.debug("Retrieved " + dgList.size() + " data getters for template '" + templateName + "'");
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Map<String, Object> dataMap = (Map<String, Object>) 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<String> names;
|
|
||||||
Object o = env.getCustomAttribute("dataGettersApplied");
|
|
||||||
if (o instanceof Set) {
|
|
||||||
names = (Set<String>) o;
|
|
||||||
} else {
|
|
||||||
names = new HashSet<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<String, Object> dataMap) throws TemplateModelException {
|
|
||||||
Map<String, Object> 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<FreemarkerRequestInfo> 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<String> nameSet = new HashSet<String>(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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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<String, FreemarkerConfiguration> themeToConfigMap = new HashMap<String, FreemarkerConfiguration>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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.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.freemarker.config.FreemarkerConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags;
|
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;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.DefaultObjectWrapper;
|
import freemarker.template.DefaultObjectWrapper;
|
||||||
import freemarker.template.TemplateModel;
|
import freemarker.template.TemplateModel;
|
||||||
import freemarker.template.TemplateModelException;
|
import freemarker.template.TemplateModelException;
|
||||||
|
@ -336,7 +338,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
private Map<String, Object> buildRequestUrls(VitroRequest vreq) {
|
private Map<String, Object> buildRequestUrls(VitroRequest vreq) {
|
||||||
Map<String, Object> requestUrls = new HashMap<String, Object>();
|
Map<String, Object> requestUrls = new HashMap<String, Object>();
|
||||||
|
|
||||||
FreemarkerConfiguration config = FreemarkerConfigurationLoader.getConfig(vreq);
|
Configuration config = FreemarkerConfiguration.getConfig(vreq);
|
||||||
TemplateModel urlModel = config.getSharedVariable("urls");
|
TemplateModel urlModel = config.getSharedVariable("urls");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,7 +13,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
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.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.core.Environment;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.Template;
|
import freemarker.template.Template;
|
||||||
|
@ -26,7 +27,7 @@ public class TemplateProcessingHelper {
|
||||||
private Configuration config = null;
|
private Configuration config = null;
|
||||||
|
|
||||||
public TemplateProcessingHelper(HttpServletRequest request, ServletContext context) {
|
public TemplateProcessingHelper(HttpServletRequest request, ServletContext context) {
|
||||||
this.config = FreemarkerConfigurationLoader.getConfig(new VitroRequest(request));
|
this.config = FreemarkerConfiguration.getConfig(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringWriter processTemplate(String templateName, Map<String, Object> map)
|
public StringWriter processTemplate(String templateName, Map<String, Object> map)
|
||||||
|
@ -50,7 +51,8 @@ public class TemplateProcessingHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply any data-getters that are associated with this template.
|
// 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.
|
// Now process it.
|
||||||
env.process();
|
env.process();
|
||||||
|
|
|
@ -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.ObjectProperty;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
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.ModelAccess;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
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.edit.n3editing.VTwo.fields.FieldVTwo;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
|
|
||||||
public class EditConfigurationUtils {
|
public class EditConfigurationUtils {
|
||||||
|
@ -272,7 +272,7 @@ public class EditConfigurationUtils {
|
||||||
//Generate HTML for a specific field name given
|
//Generate HTML for a specific field name given
|
||||||
public static String generateHTMLForElement(VitroRequest vreq, String fieldName, EditConfigurationVTwo editConfig) {
|
public static String generateHTMLForElement(VitroRequest vreq, String fieldName, EditConfigurationVTwo editConfig) {
|
||||||
String html = "";
|
String html = "";
|
||||||
Configuration fmConfig = FreemarkerConfigurationLoader.getConfig(vreq);
|
Configuration fmConfig = FreemarkerConfiguration.getConfig(vreq);
|
||||||
|
|
||||||
FieldVTwo field = editConfig == null ? null : editConfig.getField(fieldName);
|
FieldVTwo field = editConfig == null ? null : editConfig.getField(fieldName);
|
||||||
MultiValueEditSubmission editSub = EditSubmissionUtils.getEditSubmissionFromSession(vreq.getSession(), editConfig);
|
MultiValueEditSubmission editSub = EditSubmissionUtils.getEditSubmissionFromSession(vreq.getSession(), editConfig);
|
||||||
|
|
|
@ -25,9 +25,9 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfiguration;
|
import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory that creates Freemarker-based email messages.
|
* A factory that creates Freemarker-based email messages.
|
||||||
|
@ -59,8 +59,7 @@ public class FreemarkerEmailFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
FreemarkerEmailFactory factory = getFactory(vreq);
|
FreemarkerEmailFactory factory = getFactory(vreq);
|
||||||
FreemarkerConfiguration fConfig = FreemarkerConfigurationLoader
|
Configuration fConfig = FreemarkerConfiguration.getConfig(vreq);
|
||||||
.getConfig(vreq);
|
|
||||||
return new FreemarkerEmailMessage(vreq, fConfig,
|
return new FreemarkerEmailMessage(vreq, fConfig,
|
||||||
factory.getEmailSession(), factory.getReplyToAddress());
|
factory.getEmailSession(), factory.getReplyToAddress());
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
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 edu.cornell.mannlib.vitro.webapp.web.directives.EmailDirective;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
import freemarker.template.TemplateException;
|
import freemarker.template.TemplateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +49,7 @@ public class FreemarkerEmailMessage {
|
||||||
|
|
||||||
private final VitroRequest vreq;
|
private final VitroRequest vreq;
|
||||||
private final Session mailSession;
|
private final Session mailSession;
|
||||||
private final FreemarkerConfiguration config;
|
private final Configuration config;
|
||||||
|
|
||||||
private final List<Recipient> recipients = new ArrayList<Recipient>();
|
private final List<Recipient> recipients = new ArrayList<Recipient>();
|
||||||
private final InternetAddress replyToAddress;
|
private final InternetAddress replyToAddress;
|
||||||
|
@ -64,7 +64,7 @@ public class FreemarkerEmailMessage {
|
||||||
/**
|
/**
|
||||||
* Package access - should only be created by the factory.
|
* Package access - should only be created by the factory.
|
||||||
*/
|
*/
|
||||||
FreemarkerEmailMessage(VitroRequest vreq, FreemarkerConfiguration fConfig,
|
FreemarkerEmailMessage(VitroRequest vreq, Configuration fConfig,
|
||||||
Session mailSession, InternetAddress replyToAddress) {
|
Session mailSession, InternetAddress replyToAddress) {
|
||||||
this.vreq = vreq;
|
this.vreq = vreq;
|
||||||
this.mailSession = mailSession;
|
this.mailSession = mailSession;
|
||||||
|
|
|
@ -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<TemplateLoader> loaders = new ArrayList<TemplateLoader>();
|
||||||
|
|
||||||
|
// 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<String, Object> getRevisionInfo(ServletContext ctx) {
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("label", RevisionInfoBean.getBean(ctx).getReleaseLabel());
|
||||||
|
map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo"));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent sce) {
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<RequestBasedInformation> rbiRef = new ThreadLocal<>();
|
||||||
|
|
||||||
|
void setRequestInfo(HttpServletRequest req) {
|
||||||
|
rbiRef.set(new RequestBasedInformation(req, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCustomAttribute(String name) {
|
||||||
|
Map<String, Object> attribs = rbiRef.get().getCustomAttributes();
|
||||||
|
if (attribs.containsKey(name)) {
|
||||||
|
return attribs.get(name);
|
||||||
|
} else {
|
||||||
|
return super.getCustomAttribute(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getCustomAttributeNames() {
|
||||||
|
Set<String> rbiNames = rbiRef.get().getCustomAttributes().keySet();
|
||||||
|
return joinNames(rbiNames, super.getCustomAttributeNames());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemplateModel getSharedVariable(String name) {
|
||||||
|
Map<String, TemplateModel> vars = rbiRef.get().getSharedVariables();
|
||||||
|
if (vars.containsKey(name)) {
|
||||||
|
return vars.get(name);
|
||||||
|
} else {
|
||||||
|
return super.getSharedVariable(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getSharedVariableNames() {
|
||||||
|
Set<String> rbiNames = rbiRef.get().getSharedVariables().keySet();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Set<String> superNames = super.getSharedVariableNames();
|
||||||
|
|
||||||
|
Set<String> allNames = new HashSet<>(superNames);
|
||||||
|
allNames.addAll(rbiNames);
|
||||||
|
return allNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Locale getLocale() {
|
||||||
|
return rbiRef.get().getReq().getLocale();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] joinNames(Set<String> nameSet, String[] nameArray) {
|
||||||
|
Set<String> 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<DataGetter> dgList = DataGetterUtils
|
||||||
|
.getDataGettersForTemplate(vreq, vreq.getDisplayModel(),
|
||||||
|
templateName);
|
||||||
|
log.debug("Retrieved " + dgList.size()
|
||||||
|
+ " data getters for template '" + templateName + "'");
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> dataMap = (Map<String, Object>) 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<String> names;
|
||||||
|
Object o = env.getCustomAttribute("dataGettersApplied");
|
||||||
|
if (o instanceof Set) {
|
||||||
|
names = (Set<String>) o;
|
||||||
|
} else {
|
||||||
|
names = new HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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<String, Object> dataMap) throws TemplateModelException {
|
||||||
|
Map<String, Object> 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<String, Object> customAttributes = new HashMap<>();
|
||||||
|
private final Map<String, TemplateModel> 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<String, Object> getCustomAttributes() {
|
||||||
|
return customAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, TemplateModel> 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<String, String> 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<String, String> getSiteUrls(ServletContext ctx,
|
||||||
|
String themeDir) {
|
||||||
|
Map<String, String> urls = new HashMap<String, String>();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,8 +12,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
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.controller.VitroRequest;
|
import edu.cornell.mannlib.vitro.webapp.freemarker.config.FreemarkerConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerConfigurationLoader;
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils;
|
import edu.cornell.mannlib.vitro.webapp.utils.log.LogUtils;
|
||||||
import freemarker.core.ParseException;
|
import freemarker.core.ParseException;
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
|
@ -51,8 +50,7 @@ public class FreemarkerProcessingServiceImpl implements
|
||||||
throws TemplateProcessingException {
|
throws TemplateProcessingException {
|
||||||
Template template = null;
|
Template template = null;
|
||||||
try {
|
try {
|
||||||
Configuration config = FreemarkerConfigurationLoader
|
Configuration config = FreemarkerConfiguration.getConfig(req);
|
||||||
.getConfig(new VitroRequest(req));
|
|
||||||
template = config.getTemplate(templateName);
|
template = config.getTemplate(templateName);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
log.warn("Failed to parse the template at '" + templateName + "'"
|
log.warn("Failed to parse the template at '" + templateName + "'"
|
||||||
|
|
|
@ -5,8 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.commons.logging.Log;
|
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.Individual;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.Property;
|
import edu.cornell.mannlib.vitro.webapp.beans.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
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;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
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.controller.freemarker.UrlBuilder.Route;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao;
|
import edu.cornell.mannlib.vitro.webapp.dao.DataPropertyStatementDao;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
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 edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.DataPropertyListConfig;
|
||||||
import freemarker.cache.TemplateLoader;
|
import freemarker.cache.TemplateLoader;
|
||||||
|
|
||||||
|
@ -136,7 +133,7 @@ public class DataPropertyTemplateModel extends PropertyTemplateModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TemplateLoader getFreemarkerTemplateLoader() {
|
protected TemplateLoader getFreemarkerTemplateLoader() {
|
||||||
return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader();
|
return FreemarkerConfiguration.getConfig(vreq).getTemplateLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -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.ObjectProperty;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.Property;
|
import edu.cornell.mannlib.vitro.webapp.beans.Property;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
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;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
|
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.controller.freemarker.UrlBuilder.Route;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
|
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
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.InvalidConfigurationException;
|
||||||
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.PropertyListConfig;
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.customlistview.PropertyListConfig;
|
||||||
import freemarker.cache.TemplateLoader;
|
import freemarker.cache.TemplateLoader;
|
||||||
|
@ -152,7 +152,7 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
|
||||||
* This will do for now.
|
* This will do for now.
|
||||||
*/
|
*/
|
||||||
protected TemplateLoader getFreemarkerTemplateLoader() {
|
protected TemplateLoader getFreemarkerTemplateLoader() {
|
||||||
return FreemarkerConfigurationLoader.getConfig(vreq).getTemplateLoader();
|
return FreemarkerConfiguration.getConfig(vreq).getTemplateLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Map<String, String>> getStatementData() {
|
protected List<Map<String, String>> getStatementData() {
|
||||||
|
|
|
@ -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.search.solr.SolrSetup
|
||||||
|
|
||||||
edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerSetup
|
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
|
# On shutdown, this will kill the background thread started by Apache Commons File Upload
|
||||||
org.apache.commons.fileupload.servlet.FileCleanerCleanup
|
org.apache.commons.fileupload.servlet.FileCleanerCleanup
|
||||||
|
|
Loading…
Add table
Reference in a new issue