VIVO-11 Add delimiters to Freemarker templates

If enabled by an option in runtime.properties
This commit is contained in:
j2blake 2013-01-25 16:29:17 -05:00
parent bb6b2fa970
commit f350c28d24
4 changed files with 169 additions and 8 deletions

View file

@ -692,7 +692,7 @@
see the effect of changes to the template. The default is <code>false</code>, which see the effect of changes to the template. The default is <code>false</code>, which
means that a cached copy of each template will be used for 60 seconds means that a cached copy of each template will be used for 60 seconds
before the disk is checked for a new version. before the disk is checked for a new version.
<br/><b>Setting this option to "true" slows down VIVO performance.</b> <br/><b>Setting this option to "true" slows down Vitro performance.</b>
</td> </td>
</tr> </tr>
<tr class="odd_row"> <tr class="odd_row">
@ -713,7 +713,7 @@
see the effect of changes to the text strings. see the effect of changes to the text strings.
The default is <code>false</code>, which means that the language file is The default is <code>false</code>, which means that the language file is
read when VIVO starts up, or when a new theme is selected. read when VIVO starts up, or when a new theme is selected.
<br/><b>Setting this option to "true" slows down VIVO performance.</b> <br/><b>Setting this option to "true" slows down Vitro performance.</b>
</td> </td>
</tr> </tr>
<tr class="odd_row"> <tr class="odd_row">
@ -725,6 +725,24 @@
</td> </td>
</tr> </tr>
<tr>
<td colspan="2">
<b>For developers only.</b>
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 <code>false</code>.
<br/><b>Setting this option to "true" slows down Vitro performance.</b>
</td>
</tr>
<tr class="odd_row blue">
<td>
developer.insertFreemarkerDelimiters = true
</td>
<td>
false
</td>
</tr>
</tbody> </tbody>
</table> </table>
<h3 id="deploy">VI. Compile and deploy</h3> <h3 id="deploy">VI. Compile and deploy</h3>

View file

@ -141,7 +141,7 @@ RDFService.languageFilter = true
# languages.selectableLocales = en, es, fr # 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 # Defeat the Freemarker template cache, so each template is read from disk
# on each request. This permits developers to immediately see the effect of # on each request. This permits developers to immediately see the effect of
@ -152,7 +152,7 @@ RDFService.languageFilter = true
# developer.defeatFreemarkerCache = 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 # Defeat the cache of language-specific text strings, so the language file
# is read from disk on each request. This permits developers to immediately # is read from disk on each request. This permits developers to immediately
@ -162,3 +162,12 @@ RDFService.languageFilter = true
# #
# developer.defeatI18nCache = 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
# <code>false</code>.
#
# developer.insertFreemarkerDelimiters = true

View file

@ -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("<!-- FM_BEGIN ").append(dts.name).append(" -->");
sb.append(readTemplateSource(encoding, dts.ts));
sb.append("<!-- FM_END ").append(dts.name).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);
}
}
}

View file

@ -50,19 +50,21 @@ public class FreemarkerConfiguration extends Configuration {
private static final Log log = LogFactory.getLog(FreemarkerConfiguration.class); 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_DEFEAT_CACHE = "developer.defeatFreemarkerCache";
private static final String PROPERTY_DEVELOPER_INSERT_DELIMITERS = "developer.insertFreemarkerDelimiters";
private final String themeDir; private final String themeDir;
private final ServletContext context; private final ServletContext context;
private final ApplicationBean appBean; private final ApplicationBean appBean;
private final ConfigurationProperties props;
FreemarkerConfiguration(String themeDir, ApplicationBean appBean, ServletContext context) { FreemarkerConfiguration(String themeDir, ApplicationBean appBean, ServletContext context) {
this.themeDir = themeDir; this.themeDir = themeDir;
this.context = context; this.context = context;
this.appBean = appBean; this.appBean = appBean;
this.props = ConfigurationProperties.getBean(context);
String flag = ConfigurationProperties.getBean(context).getProperty( String flag = props.getProperty(PROPERTY_DEVELOPER_DEFEAT_CACHE, "false");
PROPERTY_DEVELOPER_DEFEAT_CACHE, "false");
if (Boolean.valueOf(flag.trim())) { if (Boolean.valueOf(flag.trim())) {
log.debug("Disabling Freemarker template caching in development build."); log.debug("Disabling Freemarker template caching in development build.");
setTemplateUpdateDelay(0); // no template caching in development setTemplateUpdateDelay(0); // no template caching in development
@ -211,7 +213,13 @@ public class FreemarkerConfiguration extends Configuration {
log.error("Error creating template loaders"); 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;
}
} }
/** /**