View Javadoc

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