From f350c28d2405357f24e57834c49e90ce7a569507 Mon Sep 17 00:00:00 2001 From: j2blake Date: Fri, 25 Jan 2013 16:29:17 -0500 Subject: [PATCH] VIVO-11 Add delimiters to Freemarker templates If enabled by an option in runtime.properties --- doc/install.html | 22 ++- webapp/config/example.runtime.properties | 13 +- .../freemarker/DelimitingTemplateLoader.java | 126 ++++++++++++++++++ .../freemarker/FreemarkerConfiguration.java | 16 ++- 4 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DelimitingTemplateLoader.java diff --git a/doc/install.html b/doc/install.html index 1e4064aa9..f3baf7702 100644 --- a/doc/install.html +++ b/doc/install.html @@ -692,7 +692,7 @@ see the effect of changes to the template. The default is false, which means that a cached copy of each template will be used for 60 seconds before the disk is checked for a new version. -
Setting this option to "true" slows down VIVO performance. +
Setting this option to "true" slows down Vitro performance. @@ -713,7 +713,7 @@ see the effect of changes to the text strings. The default is false, which means that the language file is read when VIVO starts up, or when a new theme is selected. -
Setting this option to "true" slows down VIVO performance. +
Setting this option to "true" slows down Vitro performance. @@ -725,6 +725,24 @@ + + + For developers only. + Add starting and ending delimiters to each Freemarker template, so you can see + which template were invoked by viewing the generated HTML. + The default is false. +
Setting this option to "true" slows down Vitro performance. + + + + + developer.insertFreemarkerDelimiters = true + + + false + + +

VI. Compile and deploy

diff --git a/webapp/config/example.runtime.properties b/webapp/config/example.runtime.properties index d0284a389..3802063d2 100644 --- a/webapp/config/example.runtime.properties +++ b/webapp/config/example.runtime.properties @@ -141,7 +141,7 @@ RDFService.languageFilter = true # languages.selectableLocales = en, es, fr # -# For developers only: Setting this option to "true" slows down VIVO performance. +# For developers only: Setting this option to "true" slows down Vitro performance. # # Defeat the Freemarker template cache, so each template is read from disk # on each request. This permits developers to immediately see the effect of @@ -152,7 +152,7 @@ RDFService.languageFilter = true # developer.defeatFreemarkerCache = true # -# For developers only: Setting this option to "true" slows down VIVO performance. +# For developers only: Setting this option to "true" slows down Vitro performance. # # Defeat the cache of language-specific text strings, so the language file # is read from disk on each request. This permits developers to immediately @@ -162,3 +162,12 @@ RDFService.languageFilter = true # # developer.defeatI18nCache = true +# +# For developers only: Setting this option to "true" slows down Vitro performance. +# +# Add starting and ending delimiters to each Freemarker template, so you can see +# which template were invoked by viewing the generated HTML. The default is +# false. +# +# developer.insertFreemarkerDelimiters = true + diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DelimitingTemplateLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DelimitingTemplateLoader.java new file mode 100644 index 000000000..a0650366e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DelimitingTemplateLoader.java @@ -0,0 +1,126 @@ +/* $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.IOException; +import java.io.Reader; +import java.io.StringReader; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import freemarker.cache.TemplateLoader; + +/** + * Wrap a TemplateLoader, so each time a template is read, delimiters will be + * inserted at the beginning and end. This makes it easier for a developer can + * see what lines of HTML come from which templates. + * + * TemplateLoader returns a token object when finding a template, and then + * recognizes that object when it is used as an argument to getLastModified() or + * getReader(). In order to keep track of the template name, we wrap the token + * object and the name in a token of our own. + * + * Taking the easy way out and reading in the entire template into a string. + * This limits the template size to less than 2^31 characters (~2 GBytes). That + * seems adequate. + */ +public class DelimitingTemplateLoader implements TemplateLoader { + private static final Log log = LogFactory + .getLog(DelimitingTemplateLoader.class); + + private final TemplateLoader innerLoader; + + public DelimitingTemplateLoader(TemplateLoader innerLoader) { + this.innerLoader = innerLoader; + } + + @Override + public Object findTemplateSource(String name) throws IOException { + Object innerTS = innerLoader.findTemplateSource(name); + if (innerTS == null) { + return null; + } else { + return new DelimitingTemplateSource(name, innerTS); + } + } + + @Override + public long getLastModified(Object templateSource) { + DelimitingTemplateSource dts = (DelimitingTemplateSource) templateSource; + return innerLoader.getLastModified(dts.ts); + } + + @Override + public Reader getReader(Object templateSource, String encoding) + throws IOException { + DelimitingTemplateSource dts = (DelimitingTemplateSource) templateSource; + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append(readTemplateSource(encoding, dts.ts)); + sb.append("\n"); + return new StringReader(sb.toString()); + } + + private StringBuilder readTemplateSource(String encoding, Object ts) + throws IOException { + StringBuilder sb = new StringBuilder(); + Reader reader = innerLoader.getReader(ts, encoding); + char[] buffer = new char[8192]; + int howmany; + while (-1 != (howmany = reader.read(buffer))) { + sb.append(buffer, 0, howmany); + } + return sb; + } + + @Override + public void closeTemplateSource(Object templateSource) throws IOException { + DelimitingTemplateSource dts = (DelimitingTemplateSource) templateSource; + innerLoader.closeTemplateSource(dts.ts); + } + + // ---------------------------------------------------------------------- + // Helper classes + // ---------------------------------------------------------------------- + + /** + * Data object, wrapping the template name and the templateSource object + * from the inner TemplateLoader. + */ + private static class DelimitingTemplateSource { + public final String name; + public final Object ts; + + public DelimitingTemplateSource(String name, Object ts) { + if (name == null) { + throw new NullPointerException("name may not be null."); + } + if (ts == null) { + throw new NullPointerException("ts may not be null."); + } + this.name = name; + this.ts = ts; + } + + @Override + public int hashCode() { + return name.hashCode() ^ ts.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null) { + return false; + } + if (!o.getClass().equals(this.getClass())) { + return false; + } + DelimitingTemplateSource that = (DelimitingTemplateSource) o; + return this.name.equals(that.name) && this.ts.equals(that.ts); + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java index 6f8f46511..c6bc10185 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java @@ -50,19 +50,21 @@ 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; - - String flag = ConfigurationProperties.getBean(context).getProperty( - PROPERTY_DEVELOPER_DEFEAT_CACHE, "false"); + 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 @@ -211,7 +213,13 @@ public class FreemarkerConfiguration extends Configuration { log.error("Error creating template loaders"); } - return mtl; + // 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; + } } /**