001: /*
002: * $Id: PortletFreemarkerResult.java 568895 2007-08-23 08:57:36Z rgielen $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts2.views.freemarker;
022:
023: import com.opensymphony.xwork2.ActionInvocation;
024: import com.opensymphony.xwork2.inject.Inject;
025: import com.opensymphony.xwork2.util.ValueStack;
026: import freemarker.template.*;
027: import org.apache.struts2.ServletActionContext;
028: import org.apache.struts2.dispatcher.StrutsResultSupport;
029: import org.apache.struts2.portlet.PortletActionConstants;
030: import org.apache.struts2.portlet.context.PortletActionContext;
031: import org.apache.struts2.views.util.ResourceUtil;
032:
033: import javax.portlet.ActionResponse;
034: import javax.portlet.PortletException;
035: import javax.servlet.ServletContext;
036: import javax.servlet.http.HttpServletRequest;
037: import javax.servlet.http.HttpServletResponse;
038: import java.io.IOException;
039: import java.io.Writer;
040: import java.util.Locale;
041:
042: /**
043: */
044: public class PortletFreemarkerResult extends StrutsResultSupport {
045:
046: private static final long serialVersionUID = -5570612389289887543L;
047:
048: protected ActionInvocation invocation;
049:
050: protected Configuration configuration;
051:
052: protected ObjectWrapper wrapper;
053: protected FreemarkerManager freemarkerManager;
054:
055: /*
056: * Struts results are constructed for each result execeution
057: *
058: * the current context is availible to subclasses via these protected fields
059: */
060: protected String location;
061:
062: private String pContentType = "text/html";
063:
064: public PortletFreemarkerResult() {
065: super ();
066: }
067:
068: public PortletFreemarkerResult(String location) {
069: super (location);
070: }
071:
072: @Inject
073: public void setFreemarkerManager(FreemarkerManager mgr) {
074: this .freemarkerManager = mgr;
075: }
076:
077: public void setContentType(String aContentType) {
078: pContentType = aContentType;
079: }
080:
081: /**
082: * allow parameterization of the contentType the default being text/html
083: */
084: public String getContentType() {
085: return pContentType;
086: }
087:
088: /**
089: * Execute this result, using the specified template location. <p/>The
090: * template location has already been interoplated for any variable
091: * substitutions <p/>this method obtains the freemarker configuration and
092: * the object wrapper from the provided hooks. It them implements the
093: * template processing workflow by calling the hooks for preTemplateProcess
094: * and postTemplateProcess
095: */
096: public void doExecute(String location, ActionInvocation invocation)
097: throws IOException, TemplateException, PortletException {
098: if (PortletActionContext.isEvent()) {
099: executeActionResult(location, invocation);
100: } else if (PortletActionContext.isRender()) {
101: executeRenderResult(location, invocation);
102: }
103: }
104:
105: /**
106: * @param location
107: * @param invocation
108: */
109: private void executeActionResult(String location,
110: ActionInvocation invocation) {
111: ActionResponse res = PortletActionContext.getActionResponse();
112: // View is rendered outside an action...uh oh...
113: res.setRenderParameter(PortletActionConstants.ACTION_PARAM,
114: "freemarkerDirect");
115: res.setRenderParameter("location", location);
116: res.setRenderParameter(PortletActionConstants.MODE_PARAM,
117: PortletActionContext.getRequest().getPortletMode()
118: .toString());
119:
120: }
121:
122: /**
123: * @param location
124: * @param invocation
125: * @throws TemplateException
126: * @throws IOException
127: * @throws TemplateModelException
128: */
129: private void executeRenderResult(String location,
130: ActionInvocation invocation) throws TemplateException,
131: IOException, TemplateModelException, PortletException {
132: this .location = location;
133: this .invocation = invocation;
134: this .configuration = getConfiguration();
135: this .wrapper = getObjectWrapper();
136:
137: HttpServletRequest req = ServletActionContext.getRequest();
138:
139: if (!location.startsWith("/")) {
140: String base = ResourceUtil.getResourceBase(req);
141: location = base + "/" + location;
142: }
143:
144: Template template = configuration.getTemplate(location,
145: deduceLocale());
146: TemplateModel model = createModel();
147: // Give subclasses a chance to hook into preprocessing
148: if (preTemplateProcess(template, model)) {
149: try {
150: // Process the template
151: PortletActionContext.getRenderResponse()
152: .setContentType(pContentType);
153: template.process(model, getWriter());
154: } finally {
155: // Give subclasses a chance to hook into postprocessing
156: postTemplateProcess(template, model);
157: }
158: }
159: }
160:
161: /**
162: * This method is called from {@link #doExecute(String, ActionInvocation)}
163: * to obtain the FreeMarker configuration object that this result will use
164: * for template loading. This is a hook that allows you to custom-configure
165: * the configuration object in a subclass, or to fetch it from an IoC
166: * container. <p/><b>The default implementation obtains the configuration
167: * from the ConfigurationManager instance. </b>
168: */
169: protected Configuration getConfiguration() throws TemplateException {
170: return freemarkerManager.getConfiguration(ServletActionContext
171: .getServletContext());
172: }
173:
174: /**
175: * This method is called from {@link #doExecute(String, ActionInvocation)}
176: * to obtain the FreeMarker object wrapper object that this result will use
177: * for adapting objects into template models. This is a hook that allows you
178: * to custom-configure the wrapper object in a subclass. <p/><b>The default
179: * implementation returns {@link Configuration#getObjectWrapper()}</b>
180: */
181: protected ObjectWrapper getObjectWrapper() {
182: return configuration.getObjectWrapper();
183: }
184:
185: /**
186: * The default writer writes directly to the response writer.
187: */
188: protected Writer getWriter() throws IOException {
189: return PortletActionContext.getRenderResponse().getWriter();
190: }
191:
192: /**
193: * Build the instance of the ScopesHashModel, including JspTagLib support
194: * <p/>Objects added to the model are <p/>
195: * <ul>
196: * <li>Application - servlet context attributes hash model
197: * <li>JspTaglibs - jsp tag lib factory model
198: * <li>Request - request attributes hash model
199: * <li>Session - session attributes hash model
200: * <li>request - the HttpServletRequst object for direct access
201: * <li>response - the HttpServletResponse object for direct access
202: * <li>stack - the OgnLValueStack instance for direct access
203: * <li>ognl - the instance of the OgnlTool
204: * <li>action - the action itself
205: * <li>exception - optional : the JSP or Servlet exception as per the
206: * servlet spec (for JSP Exception pages)
207: * <li>struts - instance of the StrutsUtil class
208: * </ul>
209: */
210: protected TemplateModel createModel() throws TemplateModelException {
211: ServletContext servletContext = ServletActionContext
212: .getServletContext();
213: HttpServletRequest request = ServletActionContext.getRequest();
214: HttpServletResponse response = ServletActionContext
215: .getResponse();
216: ValueStack stack = ServletActionContext.getContext()
217: .getValueStack();
218: return freemarkerManager.buildTemplateModel(stack, invocation
219: .getAction(), servletContext, request, response,
220: wrapper);
221: }
222:
223: /**
224: * Returns the locale used for the
225: * {@link Configuration#getTemplate(String, Locale)}call. The base
226: * implementation simply returns the locale setting of the configuration.
227: * Override this method to provide different behaviour,
228: */
229: protected Locale deduceLocale() {
230: return configuration.getLocale();
231: }
232:
233: /**
234: * the default implementation of postTemplateProcess applies the contentType
235: * parameter
236: */
237: protected void postTemplateProcess(Template template,
238: TemplateModel data) throws IOException {
239: }
240:
241: /**
242: * Called before the execution is passed to template.process(). This is a
243: * generic hook you might use in subclasses to perform a specific action
244: * before the template is processed. By default does nothing. A typical
245: * action to perform here is to inject application-specific objects into the
246: * model root
247: *
248: * @return true to process the template, false to suppress template
249: * processing.
250: */
251: protected boolean preTemplateProcess(Template template,
252: TemplateModel model) throws IOException {
253: Object attrContentType = template
254: .getCustomAttribute("content_type");
255:
256: if (attrContentType != null) {
257: ServletActionContext.getResponse().setContentType(
258: attrContentType.toString());
259: } else {
260: String contentType = getContentType();
261:
262: if (contentType == null) {
263: contentType = "text/html";
264: }
265:
266: String encoding = template.getEncoding();
267:
268: if (encoding != null) {
269: contentType = contentType + "; charset=" + encoding;
270: }
271:
272: ServletActionContext.getResponse().setContentType(
273: contentType);
274: }
275:
276: return true;
277: }
278: }
|