View Javadoc

1   /*
2    * Copyright 2000-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.portals.bridges.struts;
17  
18  import java.io.IOException;
19  import java.io.PrintWriter;
20  
21  import javax.portlet.ActionRequest;
22  import javax.portlet.ActionResponse;
23  import javax.portlet.GenericPortlet;
24  import javax.portlet.PortletConfig;
25  import javax.portlet.PortletException;
26  import javax.portlet.PortletRequest;
27  import javax.portlet.PortletResponse;
28  import javax.portlet.RenderRequest;
29  import javax.portlet.RenderResponse;
30  import javax.servlet.RequestDispatcher;
31  import javax.servlet.ServletContext;
32  import javax.servlet.ServletException;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  import javax.servlet.http.HttpSession;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.portals.bridges.common.ServletContextProvider;
40  import org.apache.portals.bridges.struts.config.StrutsPortletConfig;
41  import org.apache.portals.bridges.struts.util.EmptyHttpServletResponseWrapper;
42  
43  /***
44   * StrutsPortlet
45   * 
46   * @author <a href="mailto:ate@douma.nu">Ate Douma</a>
47   * @version $Id: StrutsPortlet.java 306954 2005-10-07 01:14:47 +0200 (Fri, 07 Oct 2005) ate $
48   */
49  public class StrutsPortlet extends GenericPortlet
50  {
51      /***
52       * Name of class implementing {@link ServletContextProvider}
53       */
54      public static final String PARAM_SERVLET_CONTEXT_PROVIDER = "ServletContextProvider";
55      /***
56       * Name of portlet preference for Struts Portlet Config Location
57       */
58      public static final String STRUTS_PORTLET_CONFIG_LOCATION = "StrutsPortletConfigLocation";
59      /***
60       * Name of portlet preference for Action page
61       */
62      public static final String PARAM_ACTION_PAGE = "ActionPage";
63      /***
64       * Name of portlet preference for Custom page
65       */
66      public static final String PARAM_CUSTOM_PAGE = "CustomPage";
67      /***
68       * Name of portlet preference for Edit page
69       */
70      public static final String PARAM_EDIT_PAGE = "EditPage";
71      /***
72       * Name of portlet preference for Edit page
73       */
74      public static final String PARAM_HELP_PAGE = "HelpPage";
75      /***
76       * Name of portlet preference for View page
77       */
78      public static final String PARAM_VIEW_PAGE = "ViewPage";
79      /***
80       * Default URL for the action page.
81       */
82      private String defaultActionPage = null;
83      /***
84       * Default URL for the custom page.
85       */
86      private String defaultCustomPage = null;
87      /***
88       * Default URL for the edit page.
89       */
90      private String defaultEditPage = null;
91      /***
92       * Default URL for the help page.
93       */
94      private String defaultHelpPage = null;
95      /***
96       * Default URL for the view page.
97       */
98      private String defaultViewPage = null;
99      private ServletContextProvider servletContextProvider;
100     private static final Log log = LogFactory.getLog(StrutsPortlet.class);
101     public static final String REQUEST_TYPE = "org.apache.portals.bridges.struts.request_type";
102     public static final String PAGE_URL = "org.apache.portals.bridges.struts.page_url";
103     public static final String ORIGIN_URL = "org.apache.portals.bridges.struts.origin_url";
104     public static final String REDIRECT_PAGE_URL = "org.apache.portals.bridges.struts.redirect_page_url";
105     public static final String REDIRECT_URL = "org.apache.portals.bridges.struts.redirect_url";
106     public static final String RENDER_CONTEXT = "org.apache.portals.bridges.struts.render_context";
107     public static final String ERROR_CONTEXT = "org.apache.portals.bridges.struts.error_context";
108     public static final String PORTLET_NAME = "org.apache.portals.bridges.struts.portlet_name";
109     public static final String STRUTS_PORTLET_CONFIG = "org.apache.portals.bridges.struts.portlet_config";
110     public static final String DEFAULT_STRUTS_PORTLET_CONFIG_LOCATION = "WEB-INF/struts-portlet-config.xml";
111     public static final String ACTION_REQUEST = "ACTION";
112     public static final String VIEW_REQUEST = "VIEW";
113     public static final String CUSTOM_REQUEST = "CUSTOM";
114     public static final String EDIT_REQUEST = "EDIT";
115     public static final String HELP_REQUEST = "HELP";
116     
117     private StrutsPortletConfig strutsPortletConfig;
118     
119     public void init(PortletConfig config) throws PortletException
120     {
121         super.init(config);
122         String contextProviderClassName = getContextProviderClassNameParameter(config);
123         if (contextProviderClassName == null)
124             throw new PortletException("Portlet " + config.getPortletName()
125                     + " is incorrectly configured. Init parameter "
126                     + PARAM_SERVLET_CONTEXT_PROVIDER + " not specified");
127         if (contextProviderClassName != null)
128         {
129             try
130             {
131                 Class clazz = Class.forName(contextProviderClassName);
132                 if (clazz != null)
133                 {
134                     Object obj = clazz.newInstance();
135                     if (ServletContextProvider.class.isInstance(obj))
136                     {
137                         servletContextProvider = (ServletContextProvider) obj;
138                     }
139                     else
140                         throw new PortletException("class not found");
141                 }
142             } catch (Exception e)
143             {
144                 if (e instanceof PortletException)
145                     throw (PortletException) e;
146                 e.printStackTrace();
147                 throw new PortletException("Cannot load", e);
148             }
149         }
150         if (servletContextProvider == null)
151             throw new PortletException("Portlet " + config.getPortletName()
152                     + " is incorrectly configured. Invalid init parameter "
153                     + PARAM_SERVLET_CONTEXT_PROVIDER + " value "
154                     + contextProviderClassName);
155         this.defaultActionPage = getActionPageParameter(config);
156         this.defaultCustomPage = getCustomPageParameter(config);
157         this.defaultEditPage = getEditPageParameter(config);
158         this.defaultViewPage = getViewPageParameter(config);
159         this.defaultHelpPage = getHelpPageParameter(config);
160         
161         if (this.defaultViewPage == null)
162         {
163             // A Struts Portlet is required to have at least the
164             // defaultViewPage
165             // defined!
166             throw new PortletException(
167                     "Portlet "
168                             + config.getPortletName()
169                             + " is incorrectly configured. No default View page is defined.");
170         }
171         if (defaultActionPage == null)
172             defaultActionPage = defaultViewPage;
173         if (defaultCustomPage == null)
174             defaultCustomPage = defaultViewPage;
175         if (defaultHelpPage == null)
176             defaultHelpPage = defaultViewPage;
177         if (defaultEditPage == null)
178             defaultEditPage = defaultViewPage;
179         
180         strutsPortletConfig = new StrutsPortletConfig();
181         String strutsPortletConfigLocation = getStrutsPortletConfigLocationParameter(config);
182         if ( strutsPortletConfigLocation == null )
183         {
184             strutsPortletConfigLocation = DEFAULT_STRUTS_PORTLET_CONFIG_LOCATION;
185         }
186         strutsPortletConfig.loadConfig(config.getPortletContext(),strutsPortletConfigLocation);
187         config.getPortletContext().setAttribute(STRUTS_PORTLET_CONFIG,strutsPortletConfig);
188     }
189     
190     protected String getContextProviderClassNameParameter(PortletConfig config)
191     {
192         return config.getInitParameter(PARAM_SERVLET_CONTEXT_PROVIDER);
193     }
194     
195     protected ServletContextProvider getServletContextProvider()
196     {
197         return servletContextProvider;
198     }
199     
200     protected ServletContext getServletContext(GenericPortlet portlet, PortletRequest request, PortletResponse response)
201     {
202         return getServletContextProvider().getServletContext(portlet);
203     }
204     
205     protected HttpServletRequest getHttpServletRequest(GenericPortlet portlet, PortletRequest request, PortletResponse response)
206     {
207         return getServletContextProvider().getHttpServletRequest(portlet, request);
208     }
209     
210     protected HttpServletResponse getHttpServletResponse(GenericPortlet portlet, PortletRequest request, PortletResponse response)
211     {
212         return getServletContextProvider().getHttpServletResponse(portlet, response);
213     }
214     
215     protected String getStrutsPageURL(PortletRequest request)
216     {
217         return request.getParameter(StrutsPortletURL.PAGE);
218     }
219     
220     protected String getStrutsOriginURL(PortletRequest request)
221     {
222         return request.getParameter(StrutsPortletURL.ORIGIN);
223     }
224     
225     protected String getActionPageParameter(PortletConfig config)
226     {
227         return config.getInitParameter(PARAM_ACTION_PAGE);
228     }
229     
230     protected String getCustomPageParameter(PortletConfig config)
231     {
232         return config.getInitParameter(PARAM_CUSTOM_PAGE);
233     }
234 
235     protected String getEditPageParameter(PortletConfig config)
236     {
237         return config.getInitParameter(PARAM_EDIT_PAGE);
238     }
239 
240     protected String getViewPageParameter(PortletConfig config)
241     {
242         return config.getInitParameter(PARAM_VIEW_PAGE);
243     }
244     
245     protected String getHelpPageParameter(PortletConfig config)
246     {
247         return config.getInitParameter(PARAM_HELP_PAGE);
248     }
249     
250     protected String getStrutsPortletConfigLocationParameter(PortletConfig config)
251     {
252         return config.getInitParameter(STRUTS_PORTLET_CONFIG_LOCATION);
253     }
254     
255     public void doEdit(RenderRequest request, RenderResponse response)
256             throws PortletException, IOException
257     {
258         processRequest(request, response, defaultEditPage, StrutsPortlet.EDIT_REQUEST);
259     }
260     public void doHelp(RenderRequest request, RenderResponse response)
261             throws PortletException, IOException
262     {
263         processRequest(request, response, defaultHelpPage, StrutsPortlet.HELP_REQUEST);
264     }
265     public void doCustom(RenderRequest request, RenderResponse response)
266             throws PortletException, IOException
267     {
268         processRequest(request, response, defaultCustomPage,
269                 StrutsPortlet.CUSTOM_REQUEST);
270     }
271     public void doView(RenderRequest request, RenderResponse response)
272             throws PortletException, IOException
273     {
274         processRequest(request, response, defaultViewPage, StrutsPortlet.VIEW_REQUEST);
275     }
276     public void processAction(ActionRequest request, ActionResponse response)
277             throws PortletException, IOException
278     {
279         processRequest(request, response, defaultActionPage,
280                 StrutsPortlet.ACTION_REQUEST);
281     }
282     protected void processRequest(PortletRequest request, PortletResponse response,
283             String defaultPage, String requestType) throws PortletException,
284             IOException
285     {
286         ServletContext servletContext = getServletContext(this, request, response);
287         HttpServletRequest req = getHttpServletRequest(this, request, response);
288         HttpServletResponse res = getHttpServletResponse(this, request, response);
289         HttpSession session = req.getSession();
290         String portletName = this.getPortletConfig().getPortletName();
291         req.setAttribute(PORTLET_NAME, portletName);
292         boolean actionRequest = (request instanceof ActionRequest);
293         
294         try
295         {
296             StrutsPortletErrorContext errorContext = (StrutsPortletErrorContext) req
297                     .getSession().getAttribute(StrutsPortlet.ERROR_CONTEXT + "_" + portletName);
298             if (errorContext != null)
299             {
300                 if (!actionRequest)
301                 {
302                     req.getSession().removeAttribute(
303                             StrutsPortlet.ERROR_CONTEXT + "_" + portletName);
304                     renderError(res, errorContext);
305                 }
306                 return;
307             }
308 
309             String keepRenderAttributes = null;
310             
311             if ( !actionRequest )
312             {
313                 keepRenderAttributes = request.getParameter(StrutsPortletURL.KEEP_RENDER_ATTRIBUTES);
314             }
315             if ( keepRenderAttributes == null )
316             {
317                 strutsPortletConfig.getRenderContextAttributes().clearAttributes(session);
318             }
319             else
320             {
321                 strutsPortletConfig.getRenderContextAttributes().restoreAttributes(req);
322             }
323                                 
324             String path = null;
325             String pageURL = getStrutsPageURL(request);
326             if (pageURL == null)
327                 path = defaultPage;
328             else
329             {
330                 path = pageURL;
331             }
332 
333             if (log.isDebugEnabled())
334                 log.debug("process path: " + path + ", requestType: " + requestType);
335 
336             RequestDispatcher rd = servletContext.getRequestDispatcher(path);
337             if (rd != null)
338             {
339                 if (actionRequest)
340                 {
341                     res = new EmptyHttpServletResponseWrapper(res);
342                     
343                     // http://issues.apache.org/jira/browse/PB-2:
344                     // provide servlet access to the Portlet components even from 
345                     // an actionRequest in extension to the JSR-168 requirement
346                     // PLT.16.3.2 which (currently) only covers renderRequest
347                     // servlet inclusion.
348                     if ( req.getAttribute("javax.portlet.config") == null )
349                     {
350                         req.setAttribute("javax.portlet.config", getPortletConfig());
351                     }
352                     if ( req.getAttribute("javax.portlet.request") == null )
353                     {
354                         req.setAttribute("javax.portlet.request", request);
355                     }
356                     if ( req.getAttribute("javax.portlet.response") == null )
357                     {
358                         req.setAttribute("javax.portlet.response", response);
359                     }
360                     String origin = getStrutsOriginURL(request);
361                     if ( origin == null )
362                     {
363                         origin = defaultPage;
364                     }
365                     request.setAttribute(StrutsPortlet.ORIGIN_URL, origin);                    
366                 }
367                 if (path != null)
368                 {
369                     req.setAttribute(StrutsPortlet.PAGE_URL, path);
370                 }
371                 
372                 req.setAttribute(StrutsPortlet.REQUEST_TYPE, requestType);
373                 try
374                 {
375                     rd.include(new PortletServletRequestWrapper(servletContext, req), res);
376                 } 
377                 catch (ServletException e)
378                 {
379                     if (log.isErrorEnabled())
380                         log.error("Include exception", e);
381                     errorContext = new StrutsPortletErrorContext();
382                     errorContext.setError(e);
383                     req.setAttribute(StrutsPortlet.ERROR_CONTEXT, errorContext);
384                     if (!actionRequest)
385                         renderError(res, errorContext);
386                 }
387                 if (actionRequest)
388                 {
389                     String renderURL;
390                     if (req.getAttribute(StrutsPortlet.ERROR_CONTEXT) != null)
391                     {
392                         pageURL = StrutsPortletURL.getOriginURL(req);
393                         if ( pageURL != null )
394                         {    
395                           ((ActionResponse) response).setRenderParameter(StrutsPortletURL.PAGE, pageURL);
396                         }
397                         if (log.isDebugEnabled())
398                             log.debug("action render error context");
399                         try
400                         {
401                             req.getSession(true).setAttribute(
402                                     StrutsPortlet.ERROR_CONTEXT + "_" + portletName,
403                                     req.getAttribute(StrutsPortlet.ERROR_CONTEXT));
404                         }
405                         catch (IllegalStateException ise)
406                         {
407                             // catch Session already invalidated exception
408                             // There isn't much we can do here other than
409                             // redirecting the user to the start page
410                         }
411                     }
412                     else
413                     {
414                         if ((renderURL = (String) req
415                                 .getAttribute(StrutsPortlet.REDIRECT_URL)) != null)
416                         {
417                             if (log.isDebugEnabled())
418                                 log.debug("action send redirect: " + renderURL);
419                             ((ActionResponse) response).sendRedirect(renderURL);
420                         } 
421                         else
422                         {
423                             strutsPortletConfig.getRenderContextAttributes().saveAttributes(req);
424                             ((ActionResponse) response).setRenderParameter(
425                                     StrutsPortletURL.KEEP_RENDER_ATTRIBUTES, "1");
426 
427                             if ((renderURL = (String) req
428                                     .getAttribute(StrutsPortlet.REDIRECT_PAGE_URL)) != null)
429                             {
430                                 if (log.isDebugEnabled())
431                                     log.debug("action render redirected page: "
432                                             + renderURL);
433                                 pageURL = renderURL;
434                             }
435                             if (pageURL != null)
436                             {
437                                 if (renderURL == null && log.isWarnEnabled())
438                                     log.warn("Warning: Using the original action URL for render URL: " +pageURL+".\nA redirect should have been issued.");
439                                 ((ActionResponse) response).setRenderParameter(
440                                         StrutsPortletURL.PAGE, pageURL);
441                             }
442                         }
443                     }
444                 }
445             }
446         } catch (IOException e)
447         {
448             if (log.isErrorEnabled())
449                 log.error("unexpected", e);
450             throw e;
451         }
452     }
453     protected void renderError(HttpServletResponse response,
454             StrutsPortletErrorContext errorContext) throws IOException
455     {
456         PrintWriter writer = response.getWriter();
457         writer.println("<hr/><h2>Error</h2>");
458         writer.println("<table border='1'>");
459         if (errorContext.getErrorCode() != 0)
460             writer.println("<tr><td valign='top'><b>Error Code</b></td><td>"
461                     + errorContext.getErrorCode() + "</td></tr>");
462         if (errorContext.getErrorMessage() != null)
463             writer.println("<tr><td valign='top'><b>Error Message</b></td><td>"
464                     + errorContext.getErrorMessage() + "</td></tr>");
465         if (errorContext.getError() != null)
466         {
467             Throwable e = errorContext.getError();
468             if (e instanceof ServletException
469                     && ((ServletException) e).getRootCause() != null)
470                 e = ((ServletException) e).getRootCause();
471             writer.print("<tr><td valign='top'><b>Error</b></td><td>"
472                     + e.getMessage() + "</td></tr>");
473             writer.print("<tr><td valign='top'><b>Error Type</b></td><td>"
474                     + e.getClass().getName() + "</td></tr>");
475             writer.print("<tr><td valign='top'><b>Stacktrace</b></td><td>");
476             StackTraceElement[] elements = e.getStackTrace();
477             StringBuffer buf = new StringBuffer();
478             for (int i = 0; i < elements.length; i++)
479                 buf.append("  " + elements[i].toString() + "<br>");
480             writer.print(buf.toString());
481             writer.println("</td></tr>");
482         }
483         writer.println("</table>");
484     }
485 }