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 }