001: /**
002: * Copyright (c) 2003-2007, David A. Czarnecki
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * Redistributions of source code must retain the above copyright notice, this list of conditions and the
009: * following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
011: * following disclaimer in the documentation and/or other materials provided with the distribution.
012: * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
013: * endorse or promote products derived from this software without specific prior written permission.
014: * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
015: * without prior written permission of David A. Czarnecki.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
018: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
019: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
021: * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
022: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
025: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
029: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030: */package org.blojsom.dispatcher.freemarker;
031:
032: import freemarker.cache.ClassTemplateLoader;
033: import freemarker.cache.FileTemplateLoader;
034: import freemarker.cache.MultiTemplateLoader;
035: import freemarker.cache.TemplateLoader;
036: import freemarker.ext.beans.BeansWrapper;
037: import freemarker.template.Configuration;
038: import freemarker.template.Template;
039: import freemarker.template.TemplateException;
040: import org.apache.commons.logging.Log;
041: import org.apache.commons.logging.LogFactory;
042: import org.blojsom.BlojsomException;
043: import org.blojsom.blog.Blog;
044: import org.blojsom.dispatcher.Dispatcher;
045: import org.blojsom.util.BlojsomConstants;
046: import org.blojsom.util.BlojsomUtils;
047:
048: import javax.servlet.ServletException;
049: import javax.servlet.ServletConfig;
050: import javax.servlet.ServletContext;
051: import javax.servlet.http.HttpServletRequest;
052: import javax.servlet.http.HttpServletResponse;
053: import java.io.File;
054: import java.io.IOException;
055: import java.io.Writer;
056: import java.util.Map;
057: import java.util.Properties;
058:
059: /**
060: * FreeMarkerDispatcher
061: *
062: * @author Dsvid Czarnecki
063: * @version $Id: FreeMarkerDispatcher.java,v 1.2 2007/01/17 01:15:46 czarneckid Exp $
064: * @since blojsom 3.0
065: */
066: public class FreeMarkerDispatcher implements Dispatcher {
067:
068: private Log _logger = LogFactory.getLog(FreeMarkerDispatcher.class);
069:
070: private Properties _freemarkerProperties;
071: private Properties _blojsomProperties;
072: private ServletConfig _servletConfig;
073:
074: private String _templatesDirectory;
075: private String _blogsDirectory;
076:
077: /**
078: * Default constructor.
079: */
080: public FreeMarkerDispatcher() {
081: }
082:
083: /**
084: * Set the Freemarker properties for use by the dispatcher
085: *
086: * @param freemarkerProperties Properties for Freemarker configuration
087: */
088: public void setFreemarkerProperties(Properties freemarkerProperties) {
089: _freemarkerProperties = freemarkerProperties;
090: }
091:
092: /**
093: * Set the properties in use by blojsom
094: *
095: * @param blojsomProperties Properties in use by blojsom
096: */
097: public void setBlojsomProperties(Properties blojsomProperties) {
098: _blojsomProperties = blojsomProperties;
099: }
100:
101: /**
102: * Set the {@link javax.servlet.ServletConfig}
103: *
104: * @param servletConfig {@link javax.servlet.ServletConfig}
105: */
106: public void setServletConfig(ServletConfig servletConfig) {
107: _servletConfig = servletConfig;
108: }
109:
110: /**
111: * Initialization method for blojsom dispatchers
112: *
113: * @param servletConfig ServletConfig for obtaining any initialization parameters
114: * @param blojsomConfiguration BlojsomConfiguration for blojsom-specific configuration information
115: * @throws org.blojsom.BlojsomException If there is an error initializing the dispatcher
116: */
117: public void init() throws BlojsomException {
118: _templatesDirectory = _blojsomProperties.getProperty(
119: BlojsomConstants.TEMPLATES_DIRECTORY_IP,
120: BlojsomConstants.DEFAULT_TEMPLATES_DIRECTORY);
121: _blogsDirectory = _blojsomProperties.getProperty(
122: BlojsomConstants.BLOGS_DIRECTORY_IP,
123: BlojsomConstants.DEFAULT_BLOGS_DIRECTORY);
124: }
125:
126: /**
127: * Set paths appropriate for loading FreeMarker templates
128: *
129: * @param blogID Blog ID
130: * @param freemarkerConfiguration
131: */
132: private void setTemplatePath(String blogID,
133: Configuration freemarkerConfiguration) {
134: ServletContext servletContext = _servletConfig
135: .getServletContext();
136:
137: try {
138: StringBuffer templatePath = new StringBuffer(
139: servletContext
140: .getRealPath(BlojsomConstants.DEFAULT_CONFIGURATION_BASE_DIRECTORY));
141: templatePath.append(_blogsDirectory).append(blogID).append(
142: _templatesDirectory);
143: FileTemplateLoader fileTemplateLoaderUser = new FileTemplateLoader(
144: new File(templatePath.toString()));
145:
146: ClassTemplateLoader classTemplateLoader = new ClassTemplateLoader(
147: getClass(), "");
148:
149: templatePath = new StringBuffer();
150: templatePath
151: .append(servletContext
152: .getRealPath(BlojsomConstants.DEFAULT_CONFIGURATION_BASE_DIRECTORY));
153: templatePath.append(BlojsomUtils
154: .removeInitialSlash(_templatesDirectory));
155: File globalTemplateDirectory = new File(templatePath
156: .toString());
157:
158: TemplateLoader[] loaders;
159: if (globalTemplateDirectory.exists()) {
160: FileTemplateLoader fileTemplateLoaderGlobal = new FileTemplateLoader(
161: globalTemplateDirectory);
162: loaders = new TemplateLoader[] {
163: fileTemplateLoaderUser,
164: fileTemplateLoaderGlobal, classTemplateLoader };
165: } else {
166: loaders = new TemplateLoader[] {
167: fileTemplateLoaderUser, classTemplateLoader };
168: }
169:
170: MultiTemplateLoader multiTemplateLoader = new MultiTemplateLoader(
171: loaders);
172: freemarkerConfiguration
173: .setTemplateLoader(multiTemplateLoader);
174: } catch (IOException e) {
175: if (_logger.isErrorEnabled()) {
176: _logger.error(e);
177: }
178: }
179: }
180:
181: /**
182: * Dispatch a request and response. A context map is provided for the BlojsomServlet to pass
183: * any required information for use by the dispatcher. The dispatcher is also
184: * provided with the template for the requested flavor along with the content type for the
185: * specific flavor.
186: *
187: * @param httpServletRequest Request
188: * @param httpServletResponse Response
189: * @param blog {@link Blog}
190: * @param context Context map
191: * @param flavorTemplate Template to dispatch to for the requested flavor
192: * @param flavorContentType Content type for the requested flavor
193: * @throws java.io.IOException If there is an exception during IO
194: * @throws javax.servlet.ServletException If there is an exception in dispatching the request
195: */
196: public void dispatch(HttpServletRequest httpServletRequest,
197: HttpServletResponse httpServletResponse, Blog blog,
198: Map context, String flavorTemplate, String flavorContentType)
199: throws IOException, ServletException {
200: httpServletResponse.setContentType(flavorContentType);
201:
202: // Configure FreeMarker with the loaded properties
203: Configuration freemarkerConfiguration = Configuration
204: .getDefaultConfiguration();
205: if (_freemarkerProperties != null) {
206: try {
207: freemarkerConfiguration
208: .setSettings(_freemarkerProperties);
209: } catch (TemplateException e) {
210: if (_logger.isErrorEnabled()) {
211: _logger.error(e);
212: }
213: }
214: }
215:
216: setTemplatePath(blog.getBlogId(), freemarkerConfiguration);
217:
218: BeansWrapper wrapper = new BeansWrapper();
219: wrapper.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY);
220: wrapper.setSimpleMapWrapper(true);
221: freemarkerConfiguration.setObjectWrapper(wrapper);
222:
223: Writer responseWriter = httpServletResponse.getWriter();
224: String flavorTemplateForPage = null;
225: String pageParameter = BlojsomUtils.getRequestValue(
226: BlojsomConstants.PAGE_PARAM, httpServletRequest, true);
227:
228: if (pageParameter != null) {
229: flavorTemplateForPage = BlojsomUtils.getTemplateForPage(
230: flavorTemplate, pageParameter);
231: if (_logger.isDebugEnabled()) {
232: _logger.debug("Retrieved template for page: "
233: + flavorTemplateForPage);
234: }
235: }
236:
237: if (flavorTemplateForPage != null) {
238: // Try and look for the flavor page template for the individual user
239: try {
240: Template template = freemarkerConfiguration
241: .getTemplate(flavorTemplateForPage);
242: template.setEncoding(BlojsomConstants.UTF8);
243: template.process(context, responseWriter);
244: } catch (Exception e) {
245: if (_logger.isErrorEnabled()) {
246: _logger.error(e);
247: }
248:
249: return;
250: }
251:
252: if (_logger.isDebugEnabled()) {
253: _logger.debug("Dispatched to flavor page template: "
254: + flavorTemplateForPage);
255: }
256: } else {
257: // Otherwise, fallback and look for the flavor template for the individual user
258: try {
259: Template template = freemarkerConfiguration
260: .getTemplate(flavorTemplate);
261: template.setEncoding(BlojsomConstants.UTF8);
262: template.process(context, responseWriter);
263: } catch (Exception e) {
264: if (_logger.isErrorEnabled()) {
265: _logger.error(e);
266: }
267:
268: return;
269: }
270:
271: if (_logger.isDebugEnabled()) {
272: _logger.debug("Dispatched to flavor template: "
273: + flavorTemplate);
274: }
275: }
276:
277: responseWriter.flush();
278: }
279: }
|