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