001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.webwork.components.template;
006:
007: import com.opensymphony.webwork.ServletActionContext;
008: import com.opensymphony.webwork.views.freemarker.FreemarkerManager;
009: import com.opensymphony.xwork.ActionContext;
010: import com.opensymphony.xwork.ActionInvocation;
011: import com.opensymphony.xwork.util.OgnlValueStack;
012: import com.opensymphony.util.ClassLoaderUtil;
013: import freemarker.template.Configuration;
014: import freemarker.template.SimpleHash;
015: import org.apache.commons.logging.Log;
016: import org.apache.commons.logging.LogFactory;
017:
018: import javax.servlet.ServletContext;
019: import javax.servlet.http.HttpServletRequest;
020: import javax.servlet.http.HttpServletResponse;
021: import java.io.IOException;
022: import java.io.Writer;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026:
027: /**
028: * Freemarker based template engine.
029: *
030: * @author CameronBraid
031: * @author tm_jee
032: */
033: public class FreemarkerTemplateEngine extends BaseTemplateEngine {
034: static Class bodyContent = null;
035:
036: static {
037: try {
038: bodyContent = ClassLoaderUtil.loadClass(
039: "javax.servlet.jsp.tagext.BodyContent",
040: FreemarkerTemplateEngine.class);
041: } catch (ClassNotFoundException e) {
042: // this is OK -- this just means JSP isn't even being used here, which is perfectly fine.
043: // we need this class in environments that use JSP to know when to wrap the writer
044: // and ignore flush() calls. In JSP, it is illegal for a BodyContent writer to be flushed(),
045: // so we have to take caution here.
046: }
047: }
048:
049: private static final Log LOG = LogFactory
050: .getLog(FreemarkerTemplateEngine.class);
051:
052: public void renderTemplate(TemplateRenderingContext templateContext)
053: throws Exception {
054: // get the various items required from the stack
055: OgnlValueStack stack = templateContext.getStack();
056: Map context = stack.getContext();
057: ServletContext servletContext = (ServletContext) context
058: .get(ServletActionContext.SERVLET_CONTEXT);
059: HttpServletRequest req = (HttpServletRequest) context
060: .get(ServletActionContext.HTTP_REQUEST);
061: HttpServletResponse res = (HttpServletResponse) context
062: .get(ServletActionContext.HTTP_RESPONSE);
063:
064: // prepare freemarker
065: FreemarkerManager freemarkerManager = FreemarkerManager
066: .getInstance();
067: Configuration config = freemarkerManager
068: .getConfiguration(servletContext);
069:
070: // get the list of templates we can use
071: List templates = templateContext.getTemplate()
072: .getPossibleTemplates(this );
073:
074: // find the right template
075: freemarker.template.Template template = null;
076: String templateName = null;
077: Exception exception = null;
078: for (Iterator iterator = templates.iterator(); iterator
079: .hasNext();) {
080: Template t = (Template) iterator.next();
081: templateName = getFinalTemplateName(t);
082: try {
083: // try to load, and if it works, stop at the first one
084: template = config.getTemplate(templateName);
085: break;
086: } catch (IOException e) {
087: if (exception == null) {
088: exception = e;
089: }
090: }
091: }
092:
093: if (template == null) {
094: LOG.error("Could not load template "
095: + templateContext.getTemplate());
096: if (exception != null) {
097: throw exception;
098: } else {
099: return;
100: }
101: }
102:
103: if (LOG.isDebugEnabled()) {
104: LOG.debug("Rendering template " + templateName);
105: }
106:
107: ActionInvocation ai = ActionContext.getContext()
108: .getActionInvocation();
109:
110: Object action = (ai == null) ? null : ai.getAction();
111: SimpleHash model = freemarkerManager.buildTemplateModel(stack,
112: action, servletContext, req, res, config
113: .getObjectWrapper());
114:
115: model.put("tag", templateContext.getTag());
116: model.put("themeProperties", getThemeProps(templateContext
117: .getTemplate()));
118:
119: // the BodyContent JSP writer doesn't like it when FM flushes automatically --
120: // so let's just not do it (it will be flushed eventually anyway)
121: Writer writer = templateContext.getWriter();
122: if (bodyContent != null
123: && bodyContent.isAssignableFrom(writer.getClass())) {
124: final Writer wrapped = writer;
125: writer = new Writer() {
126: public void write(char cbuf[], int off, int len)
127: throws IOException {
128: wrapped.write(cbuf, off, len);
129: }
130:
131: public void flush() throws IOException {
132: // nothing!
133: }
134:
135: public void close() throws IOException {
136: wrapped.close();
137: }
138: };
139: }
140:
141: try {
142: stack.push(templateContext.getTag());
143: template.process(model, writer);
144: } finally {
145: stack.pop();
146: }
147: }
148:
149: protected String getSuffix() {
150: return "ftl";
151: }
152: }
|