NIHVIVO-2164 Used shared Configuration variables to manage template data that is shared across requests and templates.
This commit is contained in:
parent
f25c835ccc
commit
428e917de9
10 changed files with 376 additions and 245 deletions
|
@ -31,9 +31,12 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet {
|
||||||
private static ServletContext context = null;
|
private static ServletContext context = null;
|
||||||
|
|
||||||
FreemarkerComponentGenerator(HttpServletRequest request) {
|
FreemarkerComponentGenerator(HttpServletRequest request) {
|
||||||
VitroRequest vreq = new VitroRequest(request);
|
|
||||||
Configuration config = getConfig(vreq);
|
// Mimic what FreemarkerHttpServlet does for a new request
|
||||||
|
VitroRequest vreq = new VitroRequest(request);
|
||||||
|
VitroFreemarkerConfiguration config = getConfig(vreq);
|
||||||
|
vreq.setAttribute("freemarkerConfig", config);
|
||||||
|
config.resetRequestSpecificSharedVariables();
|
||||||
Map<String, Object> map = getPageTemplateValues(vreq);
|
Map<String, Object> map = getPageTemplateValues(vreq);
|
||||||
|
|
||||||
request.setAttribute("ftl_head", getHead("head", map, config, vreq));
|
request.setAttribute("ftl_head", getHead("head", map, config, vreq));
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
|
@ -14,16 +10,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.beans.ApplicationBean;
|
import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean;
|
||||||
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 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.Configuration;
|
||||||
import freemarker.template.DefaultObjectWrapper;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
|
|
||||||
public class FreemarkerConfigurationLoader {
|
public class FreemarkerConfigurationLoader {
|
||||||
private static final Log log = LogFactory.getLog(FreemarkerConfigurationLoader.class);
|
private static final Log log = LogFactory.getLog(FreemarkerConfigurationLoader.class);
|
||||||
|
@ -54,9 +42,9 @@ public class FreemarkerConfigurationLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Configuration getConfig(VitroRequest vreq) {
|
public VitroFreemarkerConfiguration getConfig(VitroRequest vreq) {
|
||||||
String themeDir = getThemeDir(vreq.getAppBean());
|
String themeDir = getThemeDir(vreq.getAppBean());
|
||||||
return getConfigForTheme(themeDir);
|
return getConfigForTheme(themeDir, vreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getThemeDir(ApplicationBean appBean) {
|
protected String getThemeDir(ApplicationBean appBean) {
|
||||||
|
@ -75,12 +63,15 @@ public class FreemarkerConfigurationLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected Configuration getConfigForTheme(String themeDir) {
|
protected VitroFreemarkerConfiguration getConfigForTheme(String themeDir, VitroRequest vreq) {
|
||||||
|
|
||||||
// The template loader is theme-specific because it specifies the theme template directory as a location to
|
/* The Configuration is theme-specific because:
|
||||||
// load templates from. Thus configurations are associated with themes rather than portals.
|
* 1. The template loader is theme-specific, since it specifies a theme directory to load templates from.
|
||||||
|
* 2. Shared variables like stylesheets are theme-specific.
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Configuration> themeToConfigMap = (Map<String, Configuration>) context.getAttribute("themeToConfigMap");
|
Map<String, VitroFreemarkerConfiguration> themeToConfigMap =
|
||||||
|
(Map<String, VitroFreemarkerConfiguration>) context.getAttribute("themeToConfigMap");
|
||||||
|
|
||||||
if( themeToConfigMap == null ) {
|
if( themeToConfigMap == null ) {
|
||||||
log.error("The templating system is not configured correctly. Make sure that you have the FreemarkerSetup context listener in your web.xml.");
|
log.error("The templating system is not configured correctly. Make sure that you have the FreemarkerSetup context listener in your web.xml.");
|
||||||
|
@ -90,88 +81,10 @@ public class FreemarkerConfigurationLoader {
|
||||||
} else if (themeToConfigMap.containsKey(themeDir)) {
|
} else if (themeToConfigMap.containsKey(themeDir)) {
|
||||||
return themeToConfigMap.get(themeDir);
|
return themeToConfigMap.get(themeDir);
|
||||||
} else {
|
} else {
|
||||||
Configuration config = getNewConfig(themeDir);
|
VitroFreemarkerConfiguration config = new VitroFreemarkerConfiguration(themeDir, vreq, context);
|
||||||
themeToConfigMap.put(themeDir, config);
|
themeToConfigMap.put(themeDir, config);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Configuration getNewConfig(String themeDir) {
|
|
||||||
|
|
||||||
Configuration config = new Configuration();
|
|
||||||
|
|
||||||
String buildEnv = ConfigurationProperties.getBean(context).getProperty("Environment.build");
|
|
||||||
log.debug("Current build environment: " + buildEnv);
|
|
||||||
if ("development".equals(buildEnv)) { // Set Environment.build = development in deploy.properties
|
|
||||||
log.debug("Disabling Freemarker template caching in development build.");
|
|
||||||
config.setTemplateUpdateDelay(0); // no template caching in development
|
|
||||||
} else {
|
|
||||||
int delay = 60;
|
|
||||||
log.debug("Setting Freemarker template cache update delay to " + delay + ".");
|
|
||||||
config.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);
|
|
||||||
config.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.
|
|
||||||
config.setLocale(java.util.Locale.US);
|
|
||||||
|
|
||||||
String dateFormat = "M/d/yyyy";
|
|
||||||
config.setDateFormat(dateFormat);
|
|
||||||
String timeFormat = "h:mm a";
|
|
||||||
config.setTimeFormat(timeFormat);
|
|
||||||
config.setDateTimeFormat(dateFormat + " " + timeFormat);
|
|
||||||
|
|
||||||
//config.setNumberFormat("#,##0.##");
|
|
||||||
|
|
||||||
try {
|
|
||||||
config.setSetting("url_escaping_charset", "ISO-8859-1");
|
|
||||||
} catch (TemplateException e) {
|
|
||||||
log.error("Error setting value for url_escaping_charset.");
|
|
||||||
}
|
|
||||||
|
|
||||||
config.setTemplateLoader(getTemplateLoader(config, themeDir));
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define template locations. Template loader will look first in the theme-specific
|
|
||||||
// location, then in the vitro location.
|
|
||||||
protected final TemplateLoader getTemplateLoader(Configuration config, String themeDir) {
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
return mtl;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -43,6 +43,7 @@ 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;
|
||||||
|
import freemarker.template.utility.DeepUnwrap;
|
||||||
|
|
||||||
public class FreemarkerHttpServlet extends VitroHttpServlet {
|
public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
|
|
||||||
|
@ -82,16 +83,18 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
ResponseValues responseValues = null;
|
ResponseValues responseValues = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Configuration config = getConfig(vreq);
|
|
||||||
vreq.setAttribute("freemarkerConfig", config);
|
|
||||||
|
|
||||||
// This method does a redirect if the required authorizations are not met, so just return.
|
|
||||||
if (!isAuthorizedToDisplayPage(request, response, requiredActions(vreq))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// This method does a redirect if the required authorizations are not met, so just return.
|
||||||
|
if (!isAuthorizedToDisplayPage(request, response, requiredActions(vreq))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VitroFreemarkerConfiguration config = getConfig(vreq);
|
||||||
|
vreq.setAttribute("freemarkerConfig", config);
|
||||||
|
config.resetRequestSpecificSharedVariables();
|
||||||
|
|
||||||
responseValues = processRequest(vreq);
|
responseValues = processRequest(vreq);
|
||||||
|
|
||||||
doResponse(vreq, response, responseValues);
|
doResponse(vreq, response, responseValues);
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
@ -106,6 +109,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected void handleException(VitroRequest vreq, HttpServletResponse response, Throwable t) throws ServletException {
|
protected void handleException(VitroRequest vreq, HttpServletResponse response, Throwable t) throws ServletException {
|
||||||
try {
|
try {
|
||||||
doResponse(vreq, response, new ExceptionResponseValues(t, HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
doResponse(vreq, response, new ExceptionResponseValues(t, HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
||||||
|
@ -120,7 +124,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
doGet(request, response);
|
doGet(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Configuration getConfig(VitroRequest vreq) {
|
protected VitroFreemarkerConfiguration getConfig(VitroRequest vreq) {
|
||||||
FreemarkerConfigurationLoader loader =
|
FreemarkerConfigurationLoader loader =
|
||||||
FreemarkerConfigurationLoader.getFreemarkerConfigurationLoader(getServletContext());
|
FreemarkerConfigurationLoader.getFreemarkerConfigurationLoader(getServletContext());
|
||||||
return loader.getConfig(vreq);
|
return loader.getConfig(vreq);
|
||||||
|
@ -260,37 +264,42 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
return appBean.getThemeDir().replaceAll("/$", "");
|
return appBean.getThemeDir().replaceAll("/$", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define the URLs that are accessible to the templates. Note that we do not create menus here,
|
/**
|
||||||
// because we want the templates to be free to define the link text and where the links are displayed.
|
* Define the request-specific URLs that are accessible to the templates.
|
||||||
private final Map<String, String> getUrls(String themeDir, VitroRequest vreq) {
|
* @param VitroRequest vreq
|
||||||
Map<String, String> urls = new HashMap<String, String>();
|
*/
|
||||||
|
private void setRequestUrls(VitroRequest vreq) {
|
||||||
|
|
||||||
urls.put("home", UrlBuilder.getHomeUrl());
|
VitroFreemarkerConfiguration config = (VitroFreemarkerConfiguration)vreq.getAttribute("freemarkerConfig");
|
||||||
|
TemplateModel urlModel = config.getSharedVariable("urls");
|
||||||
|
|
||||||
// Templates use this to construct urls.
|
try {
|
||||||
urls.put("base", UrlBuilder.contextPath);
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> urls = (Map<String, Object>) DeepUnwrap.permissiveUnwrap(urlModel);
|
||||||
|
|
||||||
|
// This is request-specific because email can be configured
|
||||||
|
// and de-configured in the application interface.
|
||||||
|
if (FreemarkerEmailFactory.isConfigured(vreq)) {
|
||||||
|
urls.put("contact", UrlBuilder.getUrl(Route.CONTACT));
|
||||||
|
} else {
|
||||||
|
urls.remove("contact");
|
||||||
|
}
|
||||||
|
|
||||||
|
urls.put("currentPage", getCurrentPageUrl(vreq));
|
||||||
|
urls.put("referringPage", getReferringPageUrl(vreq));
|
||||||
|
|
||||||
|
if (PolicyHelper.isAuthorizedForActions(vreq, new EditOwnAccount())) {
|
||||||
|
urls.put("myAccount", UrlBuilder.getUrl("/accounts/myAccount"));
|
||||||
|
} else {
|
||||||
|
urls.remove("myAccount");
|
||||||
|
}
|
||||||
|
|
||||||
|
config.setSharedVariable("urls", urls);
|
||||||
|
|
||||||
urls.put("about", UrlBuilder.getUrl(Route.ABOUT));
|
} catch (TemplateModelException e) {
|
||||||
if (FreemarkerEmailFactory.isConfigured(vreq)) {
|
log.error(e, e);
|
||||||
urls.put("contact", UrlBuilder.getUrl(Route.CONTACT));
|
|
||||||
}
|
}
|
||||||
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"));
|
|
||||||
urls.put("currentPage", getCurrentPageUrl(vreq));
|
|
||||||
urls.put("referringPage", getReferringPageUrl(vreq));
|
|
||||||
|
|
||||||
if (PolicyHelper.isAuthorizedForActions(vreq, new EditOwnAccount())) {
|
|
||||||
urls.put("myAccount", UrlBuilder.getUrl("/accounts/myAccount"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return urls;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCurrentPageUrl(HttpServletRequest request) {
|
private String getCurrentPageUrl(HttpServletRequest request) {
|
||||||
|
@ -323,87 +332,28 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TemplateModel getTagList() {
|
/** Add variables that are needed to generate the page template (they will also be accessible
|
||||||
// For script and stylesheet lists, use an object wrapper that exposes write methods,
|
* to the body template). These are specific to the request, so are not defined as
|
||||||
// instead of the configuration's object wrapper, which doesn't. The templates can
|
* shared variables in the Configuration. (Though we could reset them like other
|
||||||
// add stylesheets and scripts to the lists by calling their add() methods.
|
* shared variables. These variables are not needed outside the page and body templates,
|
||||||
try {
|
* however. If they are needed elsewhere, add to shared variables.
|
||||||
return wrap(new Tags(), BeansWrapper.EXPOSE_SAFE);
|
* @param VitroRequest vreq
|
||||||
} catch (TemplateModelException e) {
|
* @return Map<String, Object>
|
||||||
log.error("Error creating Tags template model");
|
*/
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add any Java directives the templates should have access to.
|
|
||||||
* This is public and static so that these may be used by other classes during
|
|
||||||
* the transition from JSP to Freemarker.
|
|
||||||
*/
|
|
||||||
public static Map<String, Object> getDirectives() {
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
map.putAll(getDirectivesForAllEnvironments());
|
|
||||||
map.put("url", new edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective());
|
|
||||||
map.put("widget", new edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective());
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, Object> getDirectivesForAllEnvironments() {
|
|
||||||
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());
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, Object> getMethods() {
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
map.put("profileUrl", new edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod());
|
|
||||||
map.put("localName", new edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod());
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add variables that are needed to generate the page template (they will also be accessible
|
|
||||||
// to the body template).
|
|
||||||
// RY This is protected instead of private so FreeMarkerComponentGenerator can access.
|
// RY This is protected instead of private so FreeMarkerComponentGenerator can access.
|
||||||
// Once we don't need that (i.e., jsps have been eliminated) we can make it private.
|
// Once we don't need that (i.e., jsps have been eliminated) it can be made private.
|
||||||
protected Map<String, Object> getPageTemplateValues(VitroRequest vreq) {
|
protected Map<String, Object> getPageTemplateValues(VitroRequest vreq) {
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
|
||||||
ApplicationBean appBean = vreq.getAppBean();
|
|
||||||
String siteName = appBean.getApplicationName();
|
|
||||||
map.put("siteName", siteName);
|
|
||||||
|
|
||||||
// This may be overridden by the body data model received from the subcontroller.
|
// This may be overridden by the body data model received from the subcontroller.
|
||||||
map.put("title", getTitle(siteName, vreq));
|
map.put("title", getTitle(vreq.getAppBean().getApplicationName(), vreq));
|
||||||
|
|
||||||
|
setRequestUrls(vreq);
|
||||||
|
|
||||||
String themeDir = getThemeDir(appBean);
|
|
||||||
|
|
||||||
map.put("urls", getUrls(themeDir, vreq));
|
|
||||||
|
|
||||||
map.put("themeDir", themeDir);
|
|
||||||
map.put("currentTheme", themeDir.substring(themeDir.lastIndexOf('/')+1));
|
|
||||||
map.put("stylesheets", getTagList());
|
|
||||||
map.put("scripts", getTagList());
|
|
||||||
map.put("headScripts", getTagList());
|
|
||||||
|
|
||||||
map.putAll(getDirectives());
|
|
||||||
map.putAll(getMethods());
|
|
||||||
|
|
||||||
map.put("menu", getDisplayModelMenu(vreq));
|
map.put("menu", getDisplayModelMenu(vreq));
|
||||||
|
|
||||||
map.put("user", new User(vreq));
|
map.put("user", new User(vreq));
|
||||||
|
|
||||||
map.put("version", getRevisionInfo());
|
|
||||||
|
|
||||||
map.put("copyright", getCopyrightInfo(appBean));
|
|
||||||
map.put("siteTagline", appBean.getShortHand());
|
|
||||||
|
|
||||||
// This value is used only in stylesheets.ftl and already contains the context path.
|
|
||||||
map.put("stylesheetPath", UrlBuilder.getUrl(themeDir + "/css"));
|
|
||||||
|
|
||||||
String flashMessage = DisplayMessage.getMessageAndClear(vreq);
|
String flashMessage = DisplayMessage.getMessageAndClear(vreq);
|
||||||
if (! flashMessage.isEmpty()) {
|
if (! flashMessage.isEmpty()) {
|
||||||
|
@ -412,9 +362,9 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
|
|
||||||
// Let the page template know which page it's processing.
|
// Let the page template know which page it's processing.
|
||||||
map.put("currentServlet", normalizeServletName(vreq.getServletPath().replaceFirst("/", "")));
|
map.put("currentServlet", normalizeServletName(vreq.getServletPath().replaceFirst("/", "")));
|
||||||
|
|
||||||
// In template: ${now?date}, ${now?datetime}, ${now?time}
|
map.put("url", new edu.cornell.mannlib.vitro.webapp.web.directives.UrlDirective());
|
||||||
map.put("now", new Date());
|
map.put("widget", new edu.cornell.mannlib.vitro.webapp.web.directives.WidgetDirective());
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -431,30 +381,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet {
|
||||||
return vreq.getWebappDaoFactory().getMenuDao().getMainMenu(url);
|
return vreq.getWebappDaoFactory().getMenuDao().getMainMenu(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Map<String, Object> getCopyrightInfo(ApplicationBean appBean) {
|
|
||||||
|
|
||||||
Map<String, Object> copyright = null;
|
|
||||||
String copyrightText = appBean.getCopyrightAnchor();
|
|
||||||
if ( ! StringUtils.isEmpty(copyrightText) ) {
|
|
||||||
copyright = new HashMap<String, Object>();
|
|
||||||
copyright.put("text", copyrightText);
|
|
||||||
int thisYear = Calendar.getInstance().get(Calendar.YEAR); // use ${copyrightYear?c} in template
|
|
||||||
//String thisYear = ((Integer)Calendar.getInstance().get(Calendar.YEAR)).toString(); // use ${copyrightYear} in template
|
|
||||||
//SimpleDate thisYear = new SimpleDate(Calendar.getInstance().getTime(), TemplateDateModel.DATE); // use ${copyrightYear?string("yyyy")} in template
|
|
||||||
copyright.put("year", thisYear);
|
|
||||||
copyright.put("url", appBean.getCopyrightURL());
|
|
||||||
}
|
|
||||||
return copyright;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<String, Object> getRevisionInfo() {
|
|
||||||
Map<String, Object> map = new HashMap<String, Object>();
|
|
||||||
map.put("label", RevisionInfoBean.getBean(getServletContext())
|
|
||||||
.getReleaseLabel());
|
|
||||||
map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo"));
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subclasses may override. This serves as a default.
|
// Subclasses may override. This serves as a default.
|
||||||
protected String getTitle(String siteName, VitroRequest vreq) {
|
protected String getTitle(String siteName, VitroRequest vreq) {
|
||||||
return siteName;
|
return siteName;
|
||||||
|
|
|
@ -26,7 +26,7 @@ public class FreemarkerSetup implements ServletContextListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
ServletContext sc = event.getServletContext();
|
ServletContext sc = event.getServletContext();
|
||||||
sc.setAttribute("themeToConfigMap", new HashMap<String, Configuration>());
|
sc.setAttribute("themeToConfigMap", new HashMap<String, VitroFreemarkerConfiguration>());
|
||||||
BaseTemplateModel.setServletContext(sc);
|
BaseTemplateModel.setServletContext(sc);
|
||||||
FreemarkerComponentGenerator.setServletContext(sc);
|
FreemarkerComponentGenerator.setServletContext(sc);
|
||||||
UrlBuilder.contextPath = sc.getContextPath();
|
UrlBuilder.contextPath = sc.getContextPath();
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
/* $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.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
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.web.templatemodels.Tags;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.Tags.TagsBeansWrapper;
|
||||||
|
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.TemplateModel;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
|
||||||
|
public class VitroFreemarkerConfiguration extends Configuration {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(VitroFreemarkerConfiguration.class);
|
||||||
|
|
||||||
|
private final String themeDir;
|
||||||
|
private final ServletContext context;
|
||||||
|
private final ApplicationBean appBean;
|
||||||
|
private final String appName;
|
||||||
|
private final Tags stylesheets;
|
||||||
|
private final Tags scripts;
|
||||||
|
private final Tags headScripts;
|
||||||
|
|
||||||
|
VitroFreemarkerConfiguration(String themeDir, VitroRequest vreq, ServletContext context) {
|
||||||
|
|
||||||
|
this.themeDir = themeDir;
|
||||||
|
this.context = context;
|
||||||
|
this.appBean = vreq.getAppBean();
|
||||||
|
this.appName = appBean.getApplicationName();
|
||||||
|
|
||||||
|
this.stylesheets = new Tags();
|
||||||
|
this.scripts = new Tags();
|
||||||
|
this.headScripts = new Tags();
|
||||||
|
|
||||||
|
String buildEnv = ConfigurationProperties.getBean(context).getProperty("Environment.build");
|
||||||
|
log.debug("Current build environment: " + buildEnv);
|
||||||
|
if ("development".equals(buildEnv)) { // Set Environment.build = development in deploy.properties
|
||||||
|
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(vreq);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Some template variables are shared so that they are accessible to
|
||||||
|
* all templates, but they are request-specific and so need to be
|
||||||
|
* reset at the beginning of a new request.
|
||||||
|
*/
|
||||||
|
void resetRequestSpecificSharedVariables() {
|
||||||
|
stylesheets.reset();
|
||||||
|
scripts.reset();
|
||||||
|
headScripts.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are values that are accessible to all
|
||||||
|
* templates loaded by the Configuration's TemplateLoader. They
|
||||||
|
* should be application- rather than request-specific, or else get
|
||||||
|
* reset with a new request.
|
||||||
|
* @param VitroRequest vreq
|
||||||
|
*/
|
||||||
|
private void setSharedVariables(VitroRequest vreq) {
|
||||||
|
|
||||||
|
Map<String, Object> sharedVariables = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
sharedVariables.put("siteName", appName);
|
||||||
|
sharedVariables.put("version", getRevisionInfo());
|
||||||
|
sharedVariables.put("urls", getSiteUrls());
|
||||||
|
sharedVariables.put("themeDir", themeDir);
|
||||||
|
sharedVariables.put("currentTheme", themeDir.substring(themeDir.lastIndexOf('/')+1));
|
||||||
|
|
||||||
|
sharedVariables.put("stylesheets", wrapTagList(stylesheets));
|
||||||
|
sharedVariables.put("scripts", wrapTagList(scripts));
|
||||||
|
sharedVariables.put("headScripts", wrapTagList(headScripts));
|
||||||
|
|
||||||
|
sharedVariables.putAll(getDirectives());
|
||||||
|
sharedVariables.putAll(getMethods());
|
||||||
|
sharedVariables.put("copyright", getCopyrightInfo());
|
||||||
|
sharedVariables.put("siteTagline", appBean.getShortHand());
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Script and stylesheet lists are wrapped with a specialized BeansWrapper
|
||||||
|
* that exposes certain write methods, instead of the configuration's object wrapper,
|
||||||
|
* which doesn't. The templates can then add stylesheets and scripts to the lists
|
||||||
|
* by calling their add() methods.
|
||||||
|
* @param Tags tags
|
||||||
|
* @return TemplateModel
|
||||||
|
*/
|
||||||
|
private TemplateModel wrapTagList(Tags tags) {
|
||||||
|
try {
|
||||||
|
BeansWrapper wrapper = new TagsBeansWrapper();
|
||||||
|
return wrapper.wrap(tags); // this is a StringModel
|
||||||
|
} catch (TemplateModelException e) {
|
||||||
|
log.error("Error creating Tags template model");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> getDirectives() {
|
||||||
|
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());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, Object> getMethods() {
|
||||||
|
Map<String, Object> map = new HashMap<String, Object>();
|
||||||
|
map.put("profileUrl", new edu.cornell.mannlib.vitro.webapp.web.methods.IndividualProfileUrlMethod());
|
||||||
|
map.put("localName", new edu.cornell.mannlib.vitro.webapp.web.methods.IndividualLocalNameMethod());
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, Object> getCopyrightInfo() {
|
||||||
|
|
||||||
|
Map<String, Object> copyright = null;
|
||||||
|
String copyrightText = appBean.getCopyrightAnchor();
|
||||||
|
if ( ! StringUtils.isEmpty(copyrightText) ) {
|
||||||
|
copyright = new HashMap<String, Object>();
|
||||||
|
copyright.put("text", copyrightText);
|
||||||
|
int thisYear = Calendar.getInstance().get(Calendar.YEAR); // use ${copyrightYear?c} in template
|
||||||
|
//String thisYear = ((Integer)Calendar.getInstance().get(Calendar.YEAR)).toString(); // use ${copyrightYear} in template
|
||||||
|
//SimpleDate thisYear = new SimpleDate(Calendar.getInstance().getTime(), TemplateDateModel.DATE); // use ${copyrightYear?string("yyyy")} in template
|
||||||
|
copyright.put("year", thisYear);
|
||||||
|
copyright.put("url", appBean.getCopyrightURL());
|
||||||
|
}
|
||||||
|
return copyright;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
return mtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,28 +2,22 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.edit.elements;
|
package edu.cornell.mannlib.vitro.webapp.edit.elements;
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
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 org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
import org.joda.time.format.ISODateTimeFormat;
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
|
|
||||||
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
|
import com.hp.hpl.jena.datatypes.xsd.XSDDatatype;
|
||||||
import com.hp.hpl.jena.rdf.model.Literal;
|
import com.hp.hpl.jena.rdf.model.Literal;
|
||||||
import com.hp.hpl.jena.rdf.model.Model;
|
|
||||||
import com.hp.hpl.jena.rdf.model.ModelFactory;
|
|
||||||
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
import com.hp.hpl.jena.rdf.model.ResourceFactory;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.VitroFreemarkerConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
|
||||||
|
@ -116,7 +110,7 @@ public class DateTimeWithPrecision extends BaseEditElement {
|
||||||
public String draw(String fieldName, EditConfiguration editConfig,
|
public String draw(String fieldName, EditConfiguration editConfig,
|
||||||
EditSubmission editSub, Configuration fmConfig) {
|
EditSubmission editSub, Configuration fmConfig) {
|
||||||
Map map = getMapForTemplate( editConfig, editSub);
|
Map map = getMapForTemplate( editConfig, editSub);
|
||||||
map.putAll( FreemarkerHttpServlet.getDirectives());
|
//map.putAll( VitroFreemarkerConfiguration.getDirectives());
|
||||||
return merge( fmConfig, TEMPLATE_NAME, map);
|
return merge( fmConfig, TEMPLATE_NAME, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,7 @@ public class FreemarkerEmailMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processTemplate() {
|
public void processTemplate() {
|
||||||
bodyMap.putAll(FreemarkerHttpServlet.getDirectivesForAllEnvironments());
|
//bodyMap.putAll(FreemarkerHttpServlet.getDirectivesForAllEnvironments());
|
||||||
bodyMap.put("email", new EmailDirective(this));
|
bodyMap.put("email", new EmailDirective(this));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class ReadOnlyBeansWrapper extends BeansWrapper {
|
||||||
setExposureLevel(EXPOSE_SAFE);
|
setExposureLevel(EXPOSE_SAFE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
protected void finetuneMethodAppearance(Class cls, Method method, MethodAppearanceDecision decision) {
|
protected void finetuneMethodAppearance(Class cls, Method method, MethodAppearanceDecision decision) {
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,21 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.web.templatemodels;
|
package edu.cornell.mannlib.vitro.webapp.web.templatemodels;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.web.beanswrappers.ReadOnlyBeansWrapper;
|
||||||
|
import freemarker.ext.beans.BeansWrapper;
|
||||||
|
import freemarker.ext.beans.BeansWrapper.MethodAppearanceDecision;
|
||||||
|
|
||||||
public class Tags extends BaseTemplateModel {
|
public class Tags extends BaseTemplateModel {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(Tags.class);
|
||||||
|
|
||||||
protected final LinkedHashSet<String> tags;
|
protected final LinkedHashSet<String> tags;
|
||||||
|
|
||||||
public Tags() {
|
public Tags() {
|
||||||
|
@ -17,7 +26,33 @@ public class Tags extends BaseTemplateModel {
|
||||||
public Tags(LinkedHashSet<String> tags) {
|
public Tags(LinkedHashSet<String> tags) {
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
tags.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class TagsBeansWrapper extends BeansWrapper {
|
||||||
|
|
||||||
|
public TagsBeansWrapper() {
|
||||||
|
// Start by exposing all safe methods.
|
||||||
|
setExposureLevel(EXPOSE_SAFE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Override
|
||||||
|
protected void finetuneMethodAppearance(Class cls, Method method, MethodAppearanceDecision decision) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
String methodName = method.getName();
|
||||||
|
if ( ! ( methodName.equals("add") || methodName.equals("list")) ) {
|
||||||
|
decision.setExposeMethodAs(null);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Template methods */
|
/* Template methods */
|
||||||
|
|
||||||
|
@ -34,4 +69,6 @@ public class Tags extends BaseTemplateModel {
|
||||||
public String list() {
|
public String list() {
|
||||||
return StringUtils.join(tags, "");
|
return StringUtils.join(tags, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class BrowseWidget extends Widget {
|
||||||
|
|
||||||
private Map<String,Object> getCommonValues(Environment env, ServletContext context){
|
private Map<String,Object> getCommonValues(Environment env, ServletContext context){
|
||||||
Map<String,Object> values = new HashMap<String,Object>();
|
Map<String,Object> values = new HashMap<String,Object>();
|
||||||
values.putAll(FreemarkerHttpServlet.getDirectives());
|
//values.putAll(VitroFreemarkerConfiguration.getDirectives());
|
||||||
try {
|
try {
|
||||||
values.put("urls",env.getDataModel().get("urls"));
|
values.put("urls",env.getDataModel().get("urls"));
|
||||||
values.put("currentServlet", env.getDataModel().get("currentServlet"));
|
values.put("currentServlet", env.getDataModel().get("currentServlet"));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue