/* | |
* $Id: PortletFreemarkerResult.java 564599 2007-08-10 14:05:17Z nilsga $ | |
* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.struts2.views.freemarker; | |
import java.io.IOException; | |
import java.io.Writer; | |
import java.util.Locale; | |
import javax.portlet.ActionResponse; | |
import javax.portlet.PortletException; | |
import javax.portlet.PortletRequestDispatcher; | |
import javax.servlet.ServletContext; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.apache.struts2.ServletActionContext; | |
import org.apache.struts2.dispatcher.StrutsResultSupport; | |
import org.apache.struts2.portlet.PortletActionConstants; | |
import org.apache.struts2.portlet.context.PortletActionContext; | |
import org.apache.struts2.views.util.ResourceUtil; | |
import com.opensymphony.xwork2.ActionInvocation; | |
import com.opensymphony.xwork2.inject.Inject; | |
import com.opensymphony.xwork2.util.ValueStack; | |
import freemarker.template.Configuration; | |
import freemarker.template.ObjectWrapper; | |
import freemarker.template.Template; | |
import freemarker.template.TemplateException; | |
import freemarker.template.TemplateModel; | |
import freemarker.template.TemplateModelException; | |
/** | |
*/ | |
public class PortletFreemarkerResult extends StrutsResultSupport implements PortletActionConstants { | |
private static final long serialVersionUID = -5570612389289887543L; | |
protected ActionInvocation invocation; | |
protected Configuration configuration; | |
protected ObjectWrapper wrapper; | |
protected FreemarkerManager freemarkerManager; | |
/* | |
* Struts results are constructed for each result execeution | |
* | |
* the current context is availible to subclasses via these protected fields | |
*/ | |
protected String location; | |
private String pContentType = "text/html"; | |
public PortletFreemarkerResult() { | |
super(); | |
} | |
public PortletFreemarkerResult(String location) { | |
super(location); | |
} | |
@Inject | |
public void setFreemarkerManager(FreemarkerManager mgr) { | |
this.freemarkerManager = mgr; | |
} | |
public void setContentType(String aContentType) { | |
pContentType = aContentType; | |
} | |
/** | |
* allow parameterization of the contentType the default being text/html | |
*/ | |
public String getContentType() { | |
return pContentType; | |
} | |
/** | |
* Execute this result, using the specified template location. <p/>The | |
* template location has already been interoplated for any variable | |
* substitutions <p/>this method obtains the freemarker configuration and | |
* the object wrapper from the provided hooks. It them implements the | |
* template processing workflow by calling the hooks for preTemplateProcess | |
* and postTemplateProcess | |
*/ | |
public void doExecute(String location, ActionInvocation invocation) | |
throws IOException, TemplateException, PortletException { | |
if (PortletActionContext.isAction()) { | |
executeActionResult(location, invocation); | |
} else if (PortletActionContext.isRender()) { | |
executeRenderResult(location, invocation); | |
} | |
} | |
/** | |
* @param location | |
* @param invocation | |
*/ | |
private void executeActionResult(String location, | |
ActionInvocation invocation) { | |
ActionResponse res = PortletActionContext.getActionResponse(); | |
// View is rendered outside an action...uh oh... | |
invocation.getInvocationContext().getSession().put(RENDER_DIRECT_LOCATION, location); | |
res.setRenderParameter(PortletActionConstants.ACTION_PARAM, "freemarkerDirect"); | |
res.setRenderParameter("location", location); | |
res.setRenderParameter(PortletActionConstants.MODE_PARAM, PortletActionContext | |
.getRequest().getPortletMode().toString()); | |
} | |
/** | |
* @param location | |
* @param invocation | |
* @throws TemplateException | |
* @throws IOException | |
* @throws TemplateModelException | |
*/ | |
private void executeRenderResult(String location, | |
ActionInvocation invocation) throws TemplateException, IOException, | |
TemplateModelException, PortletException { | |
this.location = location; | |
this.invocation = invocation; | |
this.configuration = getConfiguration(); | |
this.wrapper = getObjectWrapper(); | |
HttpServletRequest req = ServletActionContext.getRequest(); | |
if (!location.startsWith("/")) { | |
String base = ResourceUtil.getResourceBase(req); | |
location = base + "/" + location; | |
} | |
Template template = configuration.getTemplate(location, deduceLocale()); | |
TemplateModel model = createModel(); | |
// Give subclasses a chance to hook into preprocessing | |
if (preTemplateProcess(template, model)) { | |
try { | |
// Process the template | |
PortletActionContext.getRenderResponse().setContentType(pContentType); | |
template.process(model, getWriter()); | |
} finally { | |
// Give subclasses a chance to hook into postprocessing | |
postTemplateProcess(template, model); | |
} | |
} | |
} | |
/** | |
* This method is called from {@link #doExecute(String, ActionInvocation)} | |
* to obtain the FreeMarker configuration object that this result will use | |
* for template loading. This is a hook that allows you to custom-configure | |
* the configuration object in a subclass, or to fetch it from an IoC | |
* container. <p/><b>The default implementation obtains the configuration | |
* from the ConfigurationManager instance. </b> | |
*/ | |
protected Configuration getConfiguration() throws TemplateException { | |
return freemarkerManager.getConfiguration( | |
ServletActionContext.getServletContext()); | |
} | |
/** | |
* This method is called from {@link #doExecute(String, ActionInvocation)} | |
* to obtain the FreeMarker object wrapper object that this result will use | |
* for adapting objects into template models. This is a hook that allows you | |
* to custom-configure the wrapper object in a subclass. <p/><b>The default | |
* implementation returns {@link Configuration#getObjectWrapper()}</b> | |
*/ | |
protected ObjectWrapper getObjectWrapper() { | |
return configuration.getObjectWrapper(); | |
} | |
/** | |
* The default writer writes directly to the response writer. | |
*/ | |
protected Writer getWriter() throws IOException { | |
return PortletActionContext.getRenderResponse().getWriter(); | |
} | |
/** | |
* Build the instance of the ScopesHashModel, including JspTagLib support | |
* <p/>Objects added to the model are <p/> | |
* <ul> | |
* <li>Application - servlet context attributes hash model | |
* <li>JspTaglibs - jsp tag lib factory model | |
* <li>Request - request attributes hash model | |
* <li>Session - session attributes hash model | |
* <li>request - the HttpServletRequst object for direct access | |
* <li>response - the HttpServletResponse object for direct access | |
* <li>stack - the OgnLValueStack instance for direct access | |
* <li>ognl - the instance of the OgnlTool | |
* <li>action - the action itself | |
* <li>exception - optional : the JSP or Servlet exception as per the | |
* servlet spec (for JSP Exception pages) | |
* <li>struts - instance of the StrutsUtil class | |
* </ul> | |
*/ | |
protected TemplateModel createModel() throws TemplateModelException { | |
ServletContext servletContext = ServletActionContext | |
.getServletContext(); | |
HttpServletRequest request = ServletActionContext.getRequest(); | |
HttpServletResponse response = ServletActionContext.getResponse(); | |
ValueStack stack = ServletActionContext.getContext() | |
.getValueStack(); | |
return freemarkerManager.buildTemplateModel(stack, | |
invocation.getAction(), servletContext, request, response, | |
wrapper); | |
} | |
/** | |
* Returns the locale used for the | |
* {@link Configuration#getTemplate(String, Locale)}call. The base | |
* implementation simply returns the locale setting of the configuration. | |
* Override this method to provide different behaviour, | |
*/ | |
protected Locale deduceLocale() { | |
return configuration.getLocale(); | |
} | |
/** | |
* the default implementation of postTemplateProcess applies the contentType | |
* parameter | |
*/ | |
protected void postTemplateProcess(Template template, TemplateModel data) | |
throws IOException { | |
} | |
/** | |
* Called before the execution is passed to template.process(). This is a | |
* generic hook you might use in subclasses to perform a specific action | |
* before the template is processed. By default does nothing. A typical | |
* action to perform here is to inject application-specific objects into the | |
* model root | |
* | |
* @return true to process the template, false to suppress template | |
* processing. | |
*/ | |
protected boolean preTemplateProcess(Template template, TemplateModel model) | |
throws IOException { | |
Object attrContentType = template.getCustomAttribute("content_type"); | |
if (attrContentType != null) { | |
ServletActionContext.getResponse().setContentType( | |
attrContentType.toString()); | |
} else { | |
String contentType = getContentType(); | |
if (contentType == null) { | |
contentType = "text/html"; | |
} | |
String encoding = template.getEncoding(); | |
if (encoding != null) { | |
contentType = contentType + "; charset=" + encoding; | |
} | |
ServletActionContext.getResponse().setContentType(contentType); | |
} | |
return true; | |
} | |
} | |