diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java index f239366c6..badd6c314 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerComponentGenerator.java @@ -31,9 +31,12 @@ public class FreemarkerComponentGenerator extends FreemarkerHttpServlet { private static ServletContext context = null; 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 map = getPageTemplateValues(vreq); request.setAttribute("ftl_head", getHead("head", map, config, vreq)); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java index 6d4d89fa3..532efecba 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java @@ -2,10 +2,6 @@ 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 javax.servlet.ServletContext; @@ -14,16 +10,8 @@ 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.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.DefaultObjectWrapper; -import freemarker.template.TemplateException; public class FreemarkerConfigurationLoader { 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()); - return getConfigForTheme(themeDir); + return getConfigForTheme(themeDir, vreq); } 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 - // load templates from. Thus configurations are associated with themes rather than portals. + /* The Configuration is theme-specific because: + * 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") - Map themeToConfigMap = (Map) context.getAttribute("themeToConfigMap"); + Map themeToConfigMap = + (Map) context.getAttribute("themeToConfigMap"); 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."); @@ -90,88 +81,10 @@ public class FreemarkerConfigurationLoader { } else if (themeToConfigMap.containsKey(themeDir)) { return themeToConfigMap.get(themeDir); } else { - Configuration config = getNewConfig(themeDir); + VitroFreemarkerConfiguration config = new VitroFreemarkerConfiguration(themeDir, vreq, context); themeToConfigMap.put(themeDir, 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 loaders = new ArrayList(); - MultiTemplateLoader mtl = null; - try { - // Theme template loader - String themeTemplatePath = context.getRealPath(themeDir) + "/templates"; - File themeTemplateDir = new File(themeTemplatePath); - // Handle the case where there's no theme template directory gracefully - if (themeTemplateDir.exists()) { - FileTemplateLoader themeFtl = new FileTemplateLoader(themeTemplateDir); - loaders.add(themeFtl); - } - - // Vitro template loader - String vitroTemplatePath = context.getRealPath("/templates/freemarker"); - loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath))); - - loaders.add(new ClassTemplateLoader(getClass(), "")); - - TemplateLoader[] loaderArray = loaders.toArray(new TemplateLoader[loaders.size()]); - mtl = new MultiTemplateLoader(loaderArray); - - } catch (IOException e) { - log.error("Error creating template loaders"); - } - return mtl; - - } - } \ No newline at end of file diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index b972e4327..918067a28 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -43,6 +43,7 @@ import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; +import freemarker.template.utility.DeepUnwrap; public class FreemarkerHttpServlet extends VitroHttpServlet { @@ -82,16 +83,18 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { ResponseValues responseValues = null; 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); + doResponse(vreq, response, responseValues); } catch (Throwable e) { @@ -106,6 +109,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { } } + protected void handleException(VitroRequest vreq, HttpServletResponse response, Throwable t) throws ServletException { try { doResponse(vreq, response, new ExceptionResponseValues(t, HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); @@ -120,7 +124,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { doGet(request, response); } - protected Configuration getConfig(VitroRequest vreq) { + protected VitroFreemarkerConfiguration getConfig(VitroRequest vreq) { FreemarkerConfigurationLoader loader = FreemarkerConfigurationLoader.getFreemarkerConfigurationLoader(getServletContext()); return loader.getConfig(vreq); @@ -260,37 +264,42 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { 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. - private final Map getUrls(String themeDir, VitroRequest vreq) { - Map urls = new HashMap(); + /** + * Define the request-specific URLs that are accessible to the templates. + * @param VitroRequest vreq + */ + 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. - urls.put("base", UrlBuilder.contextPath); + try { + @SuppressWarnings("unchecked") + Map urls = (Map) 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)); - if (FreemarkerEmailFactory.isConfigured(vreq)) { - urls.put("contact", UrlBuilder.getUrl(Route.CONTACT)); + } catch (TemplateModelException e) { + log.error(e, e); } - 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) { @@ -323,87 +332,28 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { return wrapper; } - private TemplateModel getTagList() { - // For script and stylesheet lists, use an object wrapper that exposes write methods, - // instead of the configuration's object wrapper, which doesn't. The templates can - // add stylesheets and scripts to the lists by calling their add() methods. - try { - return wrap(new Tags(), BeansWrapper.EXPOSE_SAFE); - } catch (TemplateModelException e) { - 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 getDirectives() { - Map map = new HashMap(); - 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 getDirectivesForAllEnvironments() { - Map map = new HashMap(); - map.put("dump", new freemarker.ext.dump.DumpDirective()); - map.put("dumpAll", new freemarker.ext.dump.DumpAllDirective()); - map.put("help", new freemarker.ext.dump.HelpDirective()); - return map; - } - - public static Map getMethods() { - Map map = new HashMap(); - 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). + /** Add variables that are needed to generate the page template (they will also be accessible + * to the body template). These are specific to the request, so are not defined as + * shared variables in the Configuration. (Though we could reset them like other + * shared variables. These variables are not needed outside the page and body templates, + * however. If they are needed elsewhere, add to shared variables. + * @param VitroRequest vreq + * @return Map + */ // 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 getPageTemplateValues(VitroRequest vreq) { Map map = new HashMap(); - - 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. - 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("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); if (! flashMessage.isEmpty()) { @@ -412,9 +362,9 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { // Let the page template know which page it's processing. map.put("currentServlet", normalizeServletName(vreq.getServletPath().replaceFirst("/", ""))); - - // In template: ${now?date}, ${now?datetime}, ${now?time} - map.put("now", new Date()); + + 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; } @@ -431,30 +381,6 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { return vreq.getWebappDaoFactory().getMenuDao().getMainMenu(url); } - private final Map getCopyrightInfo(ApplicationBean appBean) { - - Map copyright = null; - String copyrightText = appBean.getCopyrightAnchor(); - if ( ! StringUtils.isEmpty(copyrightText) ) { - copyright = new HashMap(); - 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 getRevisionInfo() { - Map map = new HashMap(); - map.put("label", RevisionInfoBean.getBean(getServletContext()) - .getReleaseLabel()); - map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo")); - return map; - } - // Subclasses may override. This serves as a default. protected String getTitle(String siteName, VitroRequest vreq) { return siteName; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java index be2c4008e..c549bb1bc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerSetup.java @@ -26,7 +26,7 @@ public class FreemarkerSetup implements ServletContextListener { } ServletContext sc = event.getServletContext(); - sc.setAttribute("themeToConfigMap", new HashMap()); + sc.setAttribute("themeToConfigMap", new HashMap()); BaseTemplateModel.setServletContext(sc); FreemarkerComponentGenerator.setServletContext(sc); UrlBuilder.contextPath = sc.getContextPath(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/VitroFreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/VitroFreemarkerConfiguration.java new file mode 100644 index 000000000..0efe0b0e7 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/VitroFreemarkerConfiguration.java @@ -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 sharedVariables = new HashMap(); + + 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 variable : sharedVariables.entrySet() ) { + try { + setSharedVariable(variable.getKey(), variable.getValue()); + } catch (TemplateModelException e) { + log.error("Could not set shared variable '" + variable.getKey() + "' in Freemarker configuration"); + } + } + } + + private final Map getRevisionInfo() { + Map map = new HashMap(); + map.put("label", RevisionInfoBean.getBean(context) + .getReleaseLabel()); + map.put("moreInfoUrl", UrlBuilder.getUrl("/revisionInfo")); + return map; + } + + private final Map getSiteUrls() { + Map urls = new HashMap(); + + // Templates use this to construct urls. + urls.put("base", context.getContextPath()); + + urls.put("home", UrlBuilder.getHomeUrl()); + urls.put("about", UrlBuilder.getUrl(Route.ABOUT)); + urls.put("search", UrlBuilder.getUrl(Route.SEARCH)); + urls.put("termsOfUse", UrlBuilder.getUrl(Route.TERMS_OF_USE)); + urls.put("login", UrlBuilder.getLoginUrl()); + urls.put("logout", UrlBuilder.getLogoutUrl()); + urls.put("siteAdmin", UrlBuilder.getUrl(Route.SITE_ADMIN)); + urls.put("themeImages", UrlBuilder.getUrl(themeDir + "/images")); + urls.put("images", UrlBuilder.getUrl("/images")); + urls.put("theme", UrlBuilder.getUrl(themeDir)); + urls.put("index", UrlBuilder.getUrl("/browse")); + + return urls; + } + + /** 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 getDirectives() { + Map map = new HashMap(); + map.put("dump", new freemarker.ext.dump.DumpDirective()); + map.put("dumpAll", new freemarker.ext.dump.DumpAllDirective()); + map.put("help", new freemarker.ext.dump.HelpDirective()); + return map; + } + + public static Map getMethods() { + Map map = new HashMap(); + 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 getCopyrightInfo() { + + Map copyright = null; + String copyrightText = appBean.getCopyrightAnchor(); + if ( ! StringUtils.isEmpty(copyrightText) ) { + copyright = new HashMap(); + 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 loaders = new ArrayList(); + MultiTemplateLoader mtl = null; + try { + // Theme template loader + String themeTemplatePath = context.getRealPath(themeDir) + "/templates"; + File themeTemplateDir = new File(themeTemplatePath); + // Handle the case where there's no theme template directory gracefully + if (themeTemplateDir.exists()) { + FileTemplateLoader themeFtl = new FileTemplateLoader(themeTemplateDir); + loaders.add(themeFtl); + } + + // Vitro template loader + String vitroTemplatePath = context.getRealPath("/templates/freemarker"); + loaders.add(new FlatteningTemplateLoader(new File(vitroTemplatePath))); + + loaders.add(new ClassTemplateLoader(getClass(), "")); + + TemplateLoader[] loaderArray = loaders.toArray(new TemplateLoader[loaders.size()]); + mtl = new MultiTemplateLoader(loaderArray); + + } catch (IOException e) { + log.error("Error creating template loaders"); + } + + return mtl; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/elements/DateTimeWithPrecision.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/elements/DateTimeWithPrecision.java index 1a5816397..321ba60f6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/elements/DateTimeWithPrecision.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/edit/elements/DateTimeWithPrecision.java @@ -2,28 +2,22 @@ package edu.cornell.mannlib.vitro.webapp.edit.elements; -import java.util.Calendar; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.Map; -import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; import org.joda.time.format.ISODateTimeFormat; import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; 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 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.edit.n3editing.configuration.EditConfiguration; 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, EditSubmission editSub, Configuration fmConfig) { Map map = getMapForTemplate( editConfig, editSub); - map.putAll( FreemarkerHttpServlet.getDirectives()); + //map.putAll( VitroFreemarkerConfiguration.getDirectives()); return merge( fmConfig, TEMPLATE_NAME, map); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java index d980dd8d7..afe12df7c 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/email/FreemarkerEmailMessage.java @@ -155,7 +155,7 @@ public class FreemarkerEmailMessage { } public void processTemplate() { - bodyMap.putAll(FreemarkerHttpServlet.getDirectivesForAllEnvironments()); + //bodyMap.putAll(FreemarkerHttpServlet.getDirectivesForAllEnvironments()); bodyMap.put("email", new EmailDirective(this)); try { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/beanswrappers/ReadOnlyBeansWrapper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/beanswrappers/ReadOnlyBeansWrapper.java index e3f921b58..d31ff1d15 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/beanswrappers/ReadOnlyBeansWrapper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/beanswrappers/ReadOnlyBeansWrapper.java @@ -28,6 +28,7 @@ public class ReadOnlyBeansWrapper extends BeansWrapper { setExposureLevel(EXPOSE_SAFE); } + @SuppressWarnings("rawtypes") @Override protected void finetuneMethodAppearance(Class cls, Method method, MethodAppearanceDecision decision) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java index 8488fd2ae..7e98ba3ca 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/Tags.java @@ -2,12 +2,21 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels; +import java.lang.reflect.Method; import java.util.LinkedHashSet; 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 { + private static final Log log = LogFactory.getLog(Tags.class); + protected final LinkedHashSet tags; public Tags() { @@ -17,7 +26,33 @@ public class Tags extends BaseTemplateModel { public Tags(LinkedHashSet 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 */ @@ -34,4 +69,6 @@ public class Tags extends BaseTemplateModel { public String list() { return StringUtils.join(tags, ""); } + + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/BrowseWidget.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/BrowseWidget.java index 1a6c419fb..86fe190c2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/BrowseWidget.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/BrowseWidget.java @@ -95,7 +95,7 @@ public class BrowseWidget extends Widget { private Map getCommonValues(Environment env, ServletContext context){ Map values = new HashMap(); - values.putAll(FreemarkerHttpServlet.getDirectives()); + //values.putAll(VitroFreemarkerConfiguration.getDirectives()); try { values.put("urls",env.getDataModel().get("urls")); values.put("currentServlet", env.getDataModel().get("currentServlet"));