View Javadoc

1   /*
2    * $Id: PortletResult.java 568895 2007-08-23 08:57:36Z rgielen $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts2.portlet.result;
22  
23  import com.opensymphony.xwork2.ActionInvocation;
24  import com.opensymphony.xwork2.util.TextUtils;
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.struts2.ServletActionContext;
28  import org.apache.struts2.dispatcher.StrutsResultSupport;
29  import org.apache.struts2.portlet.PortletActionConstants;
30  import org.apache.struts2.portlet.context.PortletActionContext;
31  
32  import javax.portlet.*;
33  import javax.servlet.ServletContext;
34  import javax.servlet.ServletException;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  import java.io.IOException;
38  import java.util.StringTokenizer;
39  import java.util.Map;
40  
41  /***
42   * Result type that includes a JSP to render.
43   *
44   */
45  public class PortletResult extends StrutsResultSupport implements PortletActionConstants {
46  
47      private static final long serialVersionUID = 434251393926178567L;
48  
49      /***
50       * Logger instance.
51       */
52      private static final Log LOG = LogFactory.getLog(PortletResult.class);
53  
54      private String contentType = "text/html";
55  
56      private String title;
57  
58      public PortletResult() {
59          super();
60      }
61  
62      public PortletResult(String location) {
63          super(location);
64      }
65  
66      /***
67       * Execute the result. Obtains the
68       * {@link javax.portlet.PortletRequestDispatcher}from the
69       * {@link PortletActionContext}and includes the JSP.
70       *
71       * @see com.opensymphony.xwork2.Result#execute(com.opensymphony.xwork2.ActionInvocation)
72       */
73      public void doExecute(String finalLocation,
74              ActionInvocation actionInvocation) throws Exception {
75  
76          if (PortletActionContext.isRender()) {
77              executeRenderResult(finalLocation);
78          } else if (PortletActionContext.isEvent()) {
79              executeActionResult(finalLocation, actionInvocation);
80          } else {
81              executeRegularServletResult(finalLocation, actionInvocation);
82          }
83      }
84  
85      /***
86       * Executes the regular servlet result.
87       *
88       * @param finalLocation
89       * @param actionInvocation
90       */
91      private void executeRegularServletResult(String finalLocation,
92              ActionInvocation actionInvocation) throws ServletException, IOException {
93          ServletContext ctx = ServletActionContext.getServletContext();
94          HttpServletRequest req = ServletActionContext.getRequest();
95          HttpServletResponse res = ServletActionContext.getResponse();
96          try {
97              ctx.getRequestDispatcher(finalLocation).include(req, res);
98          } catch (ServletException e) {
99              LOG.error("ServletException including " + finalLocation, e);
100             throw e;
101         } catch (IOException e) {
102             LOG.error("IOException while including result '" + finalLocation + "'", e);
103             throw e;
104         }
105     }
106 
107     /***
108      * Executes the action result.
109      *
110      * @param finalLocation
111      * @param invocation
112      */
113     protected void executeActionResult(String finalLocation, ActionInvocation invocation) {
114         LOG.debug("Executing result in Event phase");
115         ActionResponse res = PortletActionContext.getActionResponse();
116         Map sessionMap = invocation.getInvocationContext().getSession();
117         LOG.debug("Setting event render parameter: " + finalLocation);
118         if (finalLocation.indexOf('?') != -1) {
119             convertQueryParamsToRenderParams(res, finalLocation.substring(finalLocation.indexOf('?') + 1));
120             finalLocation = finalLocation.substring(0, finalLocation.indexOf('?'));
121         }
122         if (finalLocation.endsWith(".action")) {
123             // View is rendered with a view action...luckily...
124             finalLocation = finalLocation.substring(0, finalLocation
125                     .lastIndexOf("."));
126             res.setRenderParameter(ACTION_PARAM, finalLocation);
127         } else {
128             // View is rendered outside an action...uh oh...
129             res.setRenderParameter(PortletActionConstants.ACTION_PARAM, "renderDirect");
130             sessionMap.put(RENDER_DIRECT_LOCATION, finalLocation);
131         }
132         res.setRenderParameter(MODE_PARAM, PortletActionContext
133                 .getRequest().getPortletMode().toString());
134     }
135 
136     /***
137      * Converts the query params to render params.
138      *
139      * @param response
140      * @param queryParams
141      */
142     protected static void convertQueryParamsToRenderParams(
143             ActionResponse response, String queryParams) {
144         StringTokenizer tok = new StringTokenizer(queryParams, "&");
145         while (tok.hasMoreTokens()) {
146             String token = tok.nextToken();
147             String key = token.substring(0, token.indexOf('='));
148             String value = token.substring(token.indexOf('=') + 1);
149             response.setRenderParameter(key, value);
150         }
151     }
152 
153     /***
154      * Executes the render result.
155      *
156      * @param finalLocation
157      * @throws PortletException
158      * @throws IOException
159      */
160     protected void executeRenderResult(final String finalLocation) throws PortletException, IOException {
161         LOG.debug("Executing result in Render phase");
162         PortletConfig cfg = PortletActionContext.getPortletConfig();
163         RenderRequest req = PortletActionContext.getRenderRequest();
164         RenderResponse res = PortletActionContext.getRenderResponse();
165         LOG.debug("PortletConfig: " + cfg);
166         LOG.debug("RenderRequest: " + req);
167         LOG.debug("RenderResponse: " + res);
168         res.setContentType(contentType);
169         if (TextUtils.stringSet(title)) {
170             res.setTitle(title);
171         }
172         LOG.debug("Location: " + finalLocation);
173         PortletRequestDispatcher dispatcher = cfg.getPortletContext().getRequestDispatcher(finalLocation);
174         if(dispatcher == null) {
175             throw new PortletException("Could not locate dispatcher for '" + finalLocation + "'");
176         }
177         new IncludeTemplate() {
178             protected void when(PortletException e) {
179                 LOG.error("PortletException while dispatching to '" + finalLocation + "'");
180             }
181             protected void when(IOException e) {
182                 LOG.error("IOException while dispatching to '" + finalLocation + "'");
183             }
184         }.include(dispatcher, req, res);
185     }
186 
187     /***
188      * Sets the content type.
189      *
190      * @param contentType The content type to set.
191      */
192     public void setContentType(String contentType) {
193         this.contentType = contentType;
194     }
195 
196     /***
197      * Sets the title.
198      *
199      * @param title The title to set.
200      */
201     public void setTitle(String title) {
202         this.title = title;
203     }
204 
205     static class IncludeTemplate {
206         protected void include(PortletRequestDispatcher dispatcher, RenderRequest req, RenderResponse res) throws PortletException, IOException{
207             try {
208                 dispatcher.include(req, res);
209             }
210             catch(PortletException e) {
211                 when(e);
212                 throw e;
213             }
214             catch(IOException e) {
215                 when(e);
216                 throw e;
217             }
218         }
219 
220         protected void when(PortletException e) {}
221 
222         protected void when(IOException e) {}
223     }
224 }