| /* |
| * $Id$ |
| * |
| * 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.isEvent()) { |
| 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(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; |
| } |
| } |
| |