View Javadoc

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