001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2007
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.common.web.view.freemarker;
025:
026: import java.io.IOException;
027: import java.util.Collection;
028: import java.util.Enumeration;
029: import java.util.List;
030: import java.util.Map;
031: import java.util.Properties;
032:
033: import org.apache.commons.logging.Log;
034: import org.apache.commons.logging.LogFactory;
035: import org.springframework.context.ApplicationContext;
036: import org.springframework.context.ApplicationContextAware;
037: import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
038:
039: import freemarker.template.Configuration;
040: import freemarker.template.ObjectWrapper;
041: import freemarker.template.SimpleHash;
042: import freemarker.template.TemplateException;
043: import freemarker.template.TemplateExceptionHandler;
044:
045: /**
046: * @author Felix Gnass [fgnass at neteye dot de]
047: * @since 6.4
048: */
049: public class RiotFreeMarkerConfigurer extends FreeMarkerConfigurer
050: implements ApplicationContextAware {
051:
052: private static final Log log = LogFactory
053: .getLog(RiotFreeMarkerConfigurer.class);
054:
055: private TemplateExceptionHandler exceptionHandler = new ErrorPrintingExceptionHandler();
056:
057: private Properties macroLibraries;
058:
059: private ObjectWrapper objectWrapper;
060:
061: private Map sharedVariables;
062:
063: private boolean whitespaceStripping = false;
064:
065: private boolean useTemplateCache = true;
066:
067: private int templateUpdateDelay = 5;
068:
069: private String urlEscapingCharset = "UTF-8";
070:
071: private ApplicationContext applicationContext;
072:
073: /**
074: * Sets the macro libraries to be auto-imported, keyed by their namespace.
075: */
076: public void setMacroLibraries(Properties macroLibraries) {
077: this .macroLibraries = macroLibraries;
078: }
079:
080: /**
081: * Sets the {@link TemplateExceptionHandler} to be used. By default an
082: * {@link ErrorPrintingExceptionHandler} will be used.
083: */
084: public void setExceptionHandler(
085: TemplateExceptionHandler exceptionHandler) {
086: this .exceptionHandler = exceptionHandler;
087: }
088:
089: /**
090: * Sets the {@link ObjectWrapper} to be used. If <code>null</code>
091: * (which is the default), FreeMarker's DefaultObjectWrapper will be used.
092: */
093: public void setObjectWrapper(ObjectWrapper objectWrapper) {
094: this .objectWrapper = objectWrapper;
095: }
096:
097: /**
098: * Set a Map that contains well-known FreeMarker objects which will be passed
099: * to FreeMarker's <code>Configuration.setAllSharedVariables()</code> method.
100: * <p>
101: * Riot overrides this setter in order to set the variables in
102: * {@link #postProcessConfiguration(Configuration)}, after the custom
103: * {@link ObjectWrapper} has been set.
104: * </p>
105: * @see freemarker.template.Configuration#setAllSharedVariables
106: */
107: public void setFreemarkerVariables(Map variables) {
108: sharedVariables = variables;
109: }
110:
111: /**
112: * Sets whether the FTL parser will try to remove superfluous
113: * white-space around certain FTL tags.
114: */
115: public void setWhitespaceStripping(boolean whitespaceStripping) {
116: this .whitespaceStripping = whitespaceStripping;
117: }
118:
119: /**
120: * Sets the URL escaping charset. Allows null, which means that the
121: * output encoding will be used for URL escaping.
122: * Default is <code>UTF-8</code>.
123: */
124: public void setUrlEscapingCharset(String urlEscapingCharset) {
125: this .urlEscapingCharset = urlEscapingCharset;
126: }
127:
128: /**
129: * Sets whether the FreeMarker template cache should be used
130: * (default is <code>true</code>).
131: */
132: public void setUseTemplateCache(boolean useTemplateCache) {
133: this .useTemplateCache = useTemplateCache;
134: }
135:
136: /**
137: * Set the time in seconds that must elapse before checking whether there
138: * is a newer version of a template file. Default is <code>5</code>.
139: */
140: public void setTemplateUpdateDelay(int templateUpdateDelay) {
141: this .templateUpdateDelay = templateUpdateDelay;
142: }
143:
144: public void setApplicationContext(
145: ApplicationContext applicationContext) {
146: this .applicationContext = applicationContext;
147: }
148:
149: public void afterPropertiesSet() throws IOException,
150: TemplateException {
151: if (objectWrapper == null) {
152: Collection plugins = applicationContext.getBeansOfType(
153: ObjectWrapperPlugin.class).values();
154:
155: if (!plugins.isEmpty()) {
156: objectWrapper = new PluginObjectWrapper(plugins);
157: }
158: }
159: super .afterPropertiesSet();
160: }
161:
162: protected void postProcessTemplateLoaders(List templateLoaders) {
163: super .postProcessTemplateLoaders(templateLoaders);
164: templateLoaders.add(new ResourceTemplateLoader(
165: getResourceLoader()));
166: }
167:
168: protected void postProcessConfiguration(Configuration config)
169: throws IOException, TemplateException {
170:
171: config.setURLEscapingCharset(urlEscapingCharset);
172: config.setWhitespaceStripping(whitespaceStripping);
173: importMacroLibraries(config);
174: config.setTemplateExceptionHandler(exceptionHandler);
175: if (objectWrapper != null) {
176: config.setObjectWrapper(objectWrapper);
177: }
178:
179: if (sharedVariables != null) {
180: config.setAllSharedVariables(new SimpleHash(
181: sharedVariables, objectWrapper));
182: }
183:
184: if (useTemplateCache) {
185: config.setTemplateUpdateDelay(templateUpdateDelay);
186: } else {
187: config.setCacheStorage(new NoCacheStorage());
188: }
189: }
190:
191: protected void importMacroLibraries(Configuration config) {
192: if (macroLibraries != null) {
193: Enumeration names = macroLibraries.propertyNames();
194: while (names.hasMoreElements()) {
195: String namespace = (String) names.nextElement();
196: String lib = macroLibraries.getProperty(namespace);
197: log
198: .info(lib + " imported under namespace "
199: + namespace);
200: config.addAutoImport(namespace, lib);
201: }
202: }
203: }
204:
205: }
|