View Javadoc

    1   /*
    2    * $Id: Jsr168Dispatcher.java 498215 2007-01-20 23:59:10Z mrdon $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
    10   * with the License.  You may obtain a copy of the License at
    11   *
    12   *  http://www.apache.org/licenses/LICENSE-2.0
    13   *
    14   * Unless required by applicable law or agreed to in writing,
    15   * software distributed under the License is distributed on an
    16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    17   * KIND, either express or implied.  See the License for the
    18   * specific language governing permissions and limitations
    19   * under the License.
    20   */
    21  package org.apache.struts2.portlet.dispatcher;
    22
    23  import java.io.IOException;
    24  import java.util.Enumeration;
    25  import java.util.HashMap;
    26  import java.util.Locale;
    27  import java.util.Map;
    28
    29  import javax.portlet.ActionRequest;
    30  import javax.portlet.ActionResponse;
    31  import javax.portlet.GenericPortlet;
    32  import javax.portlet.PortletConfig;
    33  import javax.portlet.PortletException;
    34  import javax.portlet.PortletMode;
    35  import javax.portlet.PortletRequest;
    36  import javax.portlet.PortletResponse;
    37  import javax.portlet.RenderRequest;
    38  import javax.portlet.RenderResponse;
    39
    40  import org.apache.commons.logging.Log;
    41  import org.apache.commons.logging.LogFactory;
    42  import org.apache.struts2.StrutsConstants;
    43  import org.apache.struts2.StrutsException;
    44  import org.apache.struts2.StrutsStatics;
    45  import org.apache.struts2.dispatcher.ApplicationMap;
    46  import org.apache.struts2.dispatcher.Dispatcher;
    47  import org.apache.struts2.dispatcher.RequestMap;
    48  import org.apache.struts2.dispatcher.SessionMap;
    49  import org.apache.struts2.dispatcher.mapper.ActionMapper;
    50  import org.apache.struts2.dispatcher.mapper.ActionMapping;
    51  import org.apache.struts2.portlet.PortletActionConstants;
    52  import org.apache.struts2.portlet.PortletApplicationMap;
    53  import org.apache.struts2.portlet.PortletRequestMap;
    54  import org.apache.struts2.portlet.PortletSessionMap;
    55  import org.apache.struts2.portlet.context.PortletActionContext;
    56  import org.apache.struts2.portlet.context.ServletContextHolderListener;
    57  import org.apache.struts2.portlet.util.HttpServletRequestMock;
    58  import org.apache.struts2.util.AttributeMap;
    59
    60  import com.opensymphony.xwork2.util.FileManager;
    61  import com.opensymphony.xwork2.util.ValueStack;
    62  import com.opensymphony.xwork2.ActionContext;
    63  import com.opensymphony.xwork2.ActionProxy;
    64  import com.opensymphony.xwork2.ActionProxyFactory;
    65  import com.opensymphony.xwork2.config.ConfigurationException;
    66  import com.opensymphony.xwork2.inject.Container;
    67  import com.opensymphony.xwork2.util.LocalizedTextUtil;
    68  import com.opensymphony.xwork2.util.TextUtils;
    69
    70  /***
    71   * <!-- START SNIPPET: javadoc -->
    72   * <p>
    73   * Struts JSR-168 portlet dispatcher. Similar to the WW2 Servlet dispatcher,
    74   * but adjusted to a portal environment. The portlet is configured through the <tt>portlet.xml</tt>
    75   * descriptor. Examples and descriptions follow below:
    76   * </p>
    77   * <!-- END SNIPPET: javadoc -->
    78   *
    79   * @author <a href="nils-helge.garli@bekk.no">Nils-Helge Garli </a>
    80   * @author Rainer Hermanns
    81   *
    82   * <p><b>Init parameters</b></p>
    83   * <!-- START SNIPPET: params -->
    84   * <table class="confluenceTable">
    85   * <tr>
    86   *  <th class="confluenceTh">Name</th>
    87   * <th class="confluenceTh">Description</th>
    88   * <th class="confluenceTh">Default value</th>
    89   * </tr>
    90   * <tr>
    91   *  <td class="confluenceTd">portletNamespace</td><td class="confluenceTd">The namespace for the portlet in the xwork configuration. This
    92   *      namespace is prepended to all action lookups, and makes it possible to host multiple
    93   *      portlets in the same portlet application. If this parameter is set, the complete namespace
    94   *      will be <tt>/portletNamespace/modeNamespace/actionName</tt></td><td class="confluenceTd">The default namespace</td>
    95   * </tr>
    96   * <tr>
    97   *  <td class="confluenceTd">viewNamespace</td><td class="confluenceTd">Base namespace in the xwork configuration for the <tt>view</tt> portlet
    98   *      mode</td><td class="confluenceTd">The default namespace</td>
    99   * </tr>
    100  * <tr>
    101  *  <td class="confluenceTd">editNamespace</td><td class="confluenceTd">Base namespace in the xwork configuration for the <tt>edit</tt> portlet
    102  *      mode</td><td class="confluenceTd">The default namespace</td>
    103  * </tr>
    104  * <tr>
    105  *  <td class="confluenceTd">helpNamespace</td><td class="confluenceTd">Base namespace in the xwork configuration for the <tt>help</tt> portlet
    106  *      mode</td><td class="confluenceTd">The default namespace</td>
    107  * </tr>
    108  * <tr>
    109  *  <td class="confluenceTd">defaultViewAction</td><td class="confluenceTd">Default action to invoke in the <tt>view</tt> portlet mode if no action is
    110  *      specified</td><td class="confluenceTd"><tt>default</tt></td>
    111  * </tr>
    112  * <tr>
    113  *  <td class="confluenceTd">defaultEditAction</td><td class="confluenceTd">Default action to invoke in the <tt>edit</tt> portlet mode if no action is
    114  *      specified</td><td class="confluenceTd"><tt>default</tt></td>
    115  * </tr>
    116  * <tr>
    117  *  <td class="confluenceTd">defaultHelpAction</td><td class="confluenceTd">Default action to invoke in the <tt>help</tt> portlet mode if no action is
    118  *      specified</td><td class="confluenceTd"><tt>default</tt></td>
    119  * </tr>
    120  * </table>
    121  * <!-- END SNIPPET: params -->
    122  * <p><b>Example:</b></p>
    123  * <pre>
    124  * <!-- START SNIPPET: example -->
    125  *
    126  * &lt;init-param&gt;
    127  *     &lt;!-- The view mode namespace. Maps to a namespace in the xwork config file --&gt;
    128  *     &lt;name&gt;viewNamespace&lt;/name&gt;
    129  *     &lt;value&gt;/view&lt;/value&gt;
    130  * &lt;/init-param&gt;
    131  * &lt;init-param&gt;
    132  *    &lt;!-- The default action to invoke in view mode --&gt;
    133  *    &lt;name&gt;defaultViewAction&lt;/name&gt;
    134  *    &lt;value&gt;index&lt;/value&gt;
    135  * &lt;/init-param&gt;
    136  * &lt;init-param&gt;
    137  *     &lt;!-- The view mode namespace. Maps to a namespace in the xwork config file --&gt;
    138  *     &lt;name&gt;editNamespace&lt;/name&gt;
    139  *     &lt;value&gt;/edit&lt;/value&gt;
    140  * &lt;/init-param&gt;
    141  * &lt;init-param&gt;
    142  *     &lt;!-- The default action to invoke in view mode --&gt;
    143  *     &lt;name&gt;defaultEditAction&lt;/name&gt;
    144  *     &lt;value&gt;index&lt;/value&gt;
    145  * &lt;/init-param&gt;
    146  * &lt;init-param&gt;
    147  *     &lt;!-- The view mode namespace. Maps to a namespace in the xwork config file --&gt;
    148  *     &lt;name&gt;helpNamespace&lt;/name&gt;
    149  *     &lt;value&gt;/help&lt;/value&gt;
    150  * &lt;/init-param&gt;
    151  * &lt;init-param&gt;
    152  *     &lt;!-- The default action to invoke in view mode --&gt;
    153  *     &lt;name&gt;defaultHelpAction&lt;/name&gt;
    154  *     &lt;value&gt;index&lt;/value&gt;
    155  * &lt;/init-param&gt;
    156  *
    157  * <!-- END SNIPPET: example -->
    158  * </pre>
    159  */
    160 public class Jsr168Dispatcher extends GenericPortlet implements StrutsStatics,
    161         PortletActionConstants {
    162
    163     private static final Log LOG = LogFactory.getLog(Jsr168Dispatcher.class);
    164
    165     private ActionProxyFactory factory = null;
    166
    167     private Map<PortletMode,String> modeMap = new HashMap<PortletMode,String>(3);
    168
    169     private Map<PortletMode,ActionMapping> actionMap = new HashMap<PortletMode,ActionMapping>(3);
    170
    171     private String portletNamespace = null;
    172
    173     private Dispatcher dispatcherUtils;
    174
    175     private ActionMapper actionMapper;
    176
    177     /***
    178      * Initialize the portlet with the init parameters from <tt>portlet.xml</tt>
    179      */
    180     public void init(PortletConfig cfg) throws PortletException {
    181         super.init(cfg);
    182         LOG.debug("Initializing portlet " + getPortletName());
    183
    184         Map<String,String> params = new HashMap<String,String>();
    185         for (Enumeration e = cfg.getInitParameterNames(); e.hasMoreElements(); ) {
    186             String name = (String) e.nextElement();
    187             String value = cfg.getInitParameter(name);
    188             params.put(name, value);
    189         }
    190
    191         Dispatcher.setPortletSupportActive(true);
    192         dispatcherUtils = new Dispatcher(ServletContextHolderListener.getServletContext(), params);
    193         dispatcherUtils.init();
    194
    195         // For testability
    196         if (factory == null) {
    197             factory = dispatcherUtils.getConfigurationManager().getConfiguration().getContainer().getInstance(ActionProxyFactory.class);
    198         }
    199         portletNamespace = cfg.getInitParameter("portletNamespace");
    200         LOG.debug("PortletNamespace: " + portletNamespace);
    201         parseModeConfig(cfg, PortletMode.VIEW, "viewNamespace",
    202                 "defaultViewAction");
    203         parseModeConfig(cfg, PortletMode.EDIT, "editNamespace",
    204                 "defaultEditAction");
    205         parseModeConfig(cfg, PortletMode.HELP, "helpNamespace",
    206                 "defaultHelpAction");
    207         parseModeConfig(cfg, new PortletMode("config"), "configNamespace",
    208                 "defaultConfigAction");
    209         parseModeConfig(cfg, new PortletMode("about"), "aboutNamespace",
    210                 "defaultAboutAction");
    211         parseModeConfig(cfg, new PortletMode("print"), "printNamespace",
    212                 "defaultPrintAction");
    213         parseModeConfig(cfg, new PortletMode("preview"), "previewNamespace",
    214                 "defaultPreviewAction");
    215         parseModeConfig(cfg, new PortletMode("edit_defaults"),
    216                 "editDefaultsNamespace", "defaultEditDefaultsAction");
    217         if (!TextUtils.stringSet(portletNamespace)) {
    218             portletNamespace = "";
    219         }
    220         LocalizedTextUtil
    221                 .addDefaultResourceBundle("org/apache/struts2/struts-messages");
    222
    223         Container container = dispatcherUtils.getContainer();
    224         //check for configuration reloading
    225         if ("true".equalsIgnoreCase(container.getInstance(String.class, StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD))) {
    226             FileManager.setReloadingConfigs(true);
    227         }
    228
    229         actionMapper = container.getInstance(ActionMapper.class);
    230     }
    231
    232     /***
    233      * Parse the mode to namespace mappings configured in portlet.xml
    234      * @param portletConfig The PortletConfig
    235      * @param portletMode The PortletMode
    236      * @param nameSpaceParam Name of the init parameter where the namespace for the mode
    237      * is configured.
    238      * @param defaultActionParam Name of the init parameter where the default action to
    239      * execute for the mode is configured.
    240      */
    241     private void parseModeConfig(PortletConfig portletConfig,
    242             PortletMode portletMode, String nameSpaceParam,
    243             String defaultActionParam) {
    244         String namespace = portletConfig.getInitParameter(nameSpaceParam);
    245         if (!TextUtils.stringSet(namespace)) {
    246             namespace = "";
    247         }
    248         modeMap.put(portletMode, namespace);
    249         String defaultAction = portletConfig
    250                 .getInitParameter(defaultActionParam);
    251         if (!TextUtils.stringSet(defaultAction)) {
    252             defaultAction = DEFAULT_ACTION_NAME;
    253         }
    254         StringBuffer fullPath = new StringBuffer();
    255         if (TextUtils.stringSet(portletNamespace)) {
    256             fullPath.append(portletNamespace);
    257         }
    258         if (TextUtils.stringSet(namespace)) {
    259             fullPath.append(namespace).append("/");
    260         } else {
    261             fullPath.append("/");
    262         }
    263         fullPath.append(defaultAction);
    264         ActionMapping mapping = new ActionMapping();
    265         mapping.setName(getActionName(fullPath.toString()));
    266         mapping.setNamespace(getNamespace(fullPath.toString()));
    267         actionMap.put(portletMode, mapping);
    268     }
    269
    270     /***
    271      * Service an action from the <tt>event</tt> phase.
    272      *
    273      * @see javax.portlet.Portlet#processAction(javax.portlet.ActionRequest,
    274      *      javax.portlet.ActionResponse)
    275      */
    276     public void processAction(ActionRequest request, ActionResponse response)
    277             throws PortletException, IOException {
    278         LOG.debug("Entering processAction");
    279         resetActionContext();
    280         try {
    281             serviceAction(request, response, getActionMapping(request),
    282                     getRequestMap(request), getParameterMap(request),
    283                     getSessionMap(request), getApplicationMap(),
    284                     portletNamespace, EVENT_PHASE);
    285             LOG.debug("Leaving processAction");
    286         } finally {
    287             ActionContext.setContext(null);
    288         }
    289     }
    290
    291     /***
    292      * Service an action from the <tt>render</tt> phase.
    293      *
    294      * @see javax.portlet.Portlet#render(javax.portlet.RenderRequest,
    295      *      javax.portlet.RenderResponse)
    296      */
    297     public void render(RenderRequest request, RenderResponse response)
    298             throws PortletException, IOException {
    299
    300         LOG.debug("Entering render");
    301         resetActionContext();
    302         response.setTitle(getTitle(request));
    303         try {
    304             // Check to see if an event set the render to be included directly
    305             serviceAction(request, response, getActionMapping(request),
    306                     getRequestMap(request), getParameterMap(request),
    307                     getSessionMap(request), getApplicationMap(),
    308                     portletNamespace, RENDER_PHASE);
    309             LOG.debug("Leaving render");
    310         } finally {
    311             resetActionContext();
    312         }
    313     }
    314
    315     /***
    316      *  Reset the action context.
    317      */
    318     private void resetActionContext() {
    319         ActionContext.setContext(null);
    320     }
    321
    322     /***
    323      * Merges all application and portlet attributes into a single
    324      * <tt>HashMap</tt> to represent the entire <tt>Action</tt> context.
    325      *
    326      * @param requestMap a Map of all request attributes.
    327      * @param parameterMap a Map of all request parameters.
    328      * @param sessionMap a Map of all session attributes.
    329      * @param applicationMap a Map of all servlet context attributes.
    330      * @param request the PortletRequest object.
    331      * @param response the PortletResponse object.
    332      * @param portletConfig the PortletConfig object.
    333      * @param phase The portlet phase (render or action, see
    334      *        {@link PortletActionConstants})
    335      * @return a HashMap representing the <tt>Action</tt> context.
    336      */
    337     public HashMap createContextMap(Map requestMap, Map parameterMap,
    338             Map sessionMap, Map applicationMap, PortletRequest request,
    339             PortletResponse response, PortletConfig portletConfig, Integer phase) {
    340
    341         // TODO Must put http request/response objects into map for use with
    342         // ServletActionContext
    343         HashMap<String,Object> extraContext = new HashMap<String,Object>();
    344         extraContext.put(ActionContext.PARAMETERS, parameterMap);
    345         extraContext.put(ActionContext.SESSION, sessionMap);
    346         extraContext.put(ActionContext.APPLICATION, applicationMap);
    347
    348         String defaultLocale = dispatcherUtils.getContainer().getInstance(String.class, StrutsConstants.STRUTS_LOCALE);
    349         Locale locale = null;
    350         if (defaultLocale != null) {
    351             locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
    352         } else {
    353             locale = request.getLocale();
    354         }
    355         extraContext.put(ActionContext.LOCALE, locale);
    356
    357         extraContext.put(StrutsStatics.STRUTS_PORTLET_CONTEXT, getPortletContext());
    358         extraContext.put(REQUEST, request);
    359         extraContext.put(RESPONSE, response);
    360         extraContext.put(PORTLET_CONFIG, portletConfig);
    361         extraContext.put(PORTLET_NAMESPACE, portletNamespace);
    362         extraContext.put(DEFAULT_ACTION_FOR_MODE, actionMap.get(request.getPortletMode()));
    363         // helpers to get access to request/session/application scope
    364         extraContext.put("request", requestMap);
    365         extraContext.put("session", sessionMap);
    366         extraContext.put("application", applicationMap);
    367         extraContext.put("parameters", parameterMap);
    368         extraContext.put(MODE_NAMESPACE_MAP, modeMap);
    369
    370         extraContext.put(PHASE, phase);
    371
    372         AttributeMap attrMap = new AttributeMap(extraContext);
    373         extraContext.put("attr", attrMap);
    374
    375         return extraContext;
    376     }
    377
    378     /***
    379      * Loads the action and executes it. This method first creates the action
    380      * context from the given parameters then loads an <tt>ActionProxy</tt>
    381      * from the given action name and namespace. After that, the action is
    382      * executed and output channels throught the response object.
    383      *
    384      * @param request the HttpServletRequest object.
    385      * @param response the HttpServletResponse object.
    386      * @param mapping the action mapping.
    387      * @param requestMap a Map of request attributes.
    388      * @param parameterMap a Map of request parameters.
    389      * @param sessionMap a Map of all session attributes.
    390      * @param applicationMap a Map of all application attributes.
    391      * @param portletNamespace the namespace or context of the action.
    392      * @param phase The portlet phase (render or action, see
    393      *        {@link PortletActionConstants})
    394      */
    395     public void serviceAction(PortletRequest request, PortletResponse response,
    396             ActionMapping mapping, Map requestMap, Map parameterMap,
    397             Map sessionMap, Map applicationMap, String portletNamespace,
    398             Integer phase) throws PortletException {
    399         LOG.debug("serviceAction");
    400         HashMap extraContext = createContextMap(requestMap, parameterMap,
    401                 sessionMap, applicationMap, request, response,
    402                 getPortletConfig(), phase);
    403         String actionName = mapping.getName();
    404         String namespace = mapping.getNamespace();
    405         Dispatcher.setInstance(dispatcherUtils);
    406         try {
    407             LOG.debug("Creating action proxy for name = " + actionName
    408                     + ", namespace = " + namespace);
    409             ActionProxy proxy = factory.createActionProxy(namespace,
    410                     actionName, extraContext);
    411             proxy.setMethod(mapping.getMethod());
    412             request.setAttribute("struts.valueStack", proxy.getInvocation()
    413                     .getStack());
    414             if (PortletActionConstants.RENDER_PHASE.equals(phase)
    415                     && TextUtils.stringSet(request
    416                             .getParameter(EVENT_ACTION))) {
    417
    418                 ActionProxy action = (ActionProxy) request.getPortletSession()
    419                         .getAttribute(EVENT_ACTION);
    420                 if (action != null) {
    421                     ValueStack stack = proxy.getInvocation().getStack();
    422                     Object top = stack.pop();
    423                     stack.push(action.getInvocation().getAction());
    424                     stack.push(top);
    425                 }
    426             }
    427             proxy.execute();
    428             if (PortletActionConstants.EVENT_PHASE.equals(phase)) {
    429                 // Store the executed action in the session for retrieval in the
    430                 // render phase.
    431                 ActionResponse actionResp = (ActionResponse) response;
    432                 request.getPortletSession().setAttribute(EVENT_ACTION, proxy);
    433                 actionResp.setRenderParameter(EVENT_ACTION, "true");
    434             }
    435         } catch (ConfigurationException e) {
    436             LOG.error("Could not find action", e);
    437             throw new PortletException("Could not find action " + actionName, e);
    438         } catch (Exception e) {
    439             LOG.error("Could not execute action", e);
    440             throw new PortletException("Error executing action " + actionName,
    441                     e);
    442         } finally {
    443             Dispatcher.setInstance(null);
    444         }
    445     }
    446
    447     /***
    448      * Returns a Map of all application attributes. Copies all attributes from
    449      * the {@link PortletActionContext}into an {@link ApplicationMap}.
    450      *
    451      * @return a Map of all application attributes.
    452      */
    453     protected Map getApplicationMap() {
    454         return new PortletApplicationMap(getPortletContext());
    455     }
    456
    457     /***
    458      * Gets the namespace of the action from the request. The namespace is the
    459      * same as the portlet mode. E.g, view mode is mapped to namespace
    460      * <code>view</code>, and edit mode is mapped to the namespace
    461      * <code>edit</code>
    462      *
    463      * @param request the PortletRequest object.
    464      * @return the namespace of the action.
    465      */
    466     protected ActionMapping getActionMapping(final PortletRequest request) {
    467         ActionMapping mapping = null;
    468         String actionPath = null;
    469         if (resetAction(request)) {
    470             mapping = (ActionMapping) actionMap.get(request.getPortletMode());
    471         } else {
    472             actionPath = request.getParameter(ACTION_PARAM);
    473             if (!TextUtils.stringSet(actionPath)) {
    474                 mapping = (ActionMapping) actionMap.get(request
    475                         .getPortletMode());
    476             } else {
    477
    478                 // Use the usual action mapper, but it is expecting an action extension
    479                 // on the uri, so we add the default one, which should be ok as the
    480                 // portlet is a portlet first, a servlet second
    481                 HttpServletRequestMock httpRequest = new HttpServletRequestMock()
    482                     .setServletPath(actionPath + ".action")
    483                     .setParameterMap(request.getParameterMap());
    484                 mapping = actionMapper.getMapping(httpRequest, dispatcherUtils.getConfigurationManager());
    485             }
    486         }
    487
    488         if (mapping == null) {
    489             throw new StrutsException("Unable to locate action mapping for request, probably due to " +
    490                     "an invalid action path: "+actionPath);
    491         }
    492         return mapping;
    493     }
    494
    495     /***
    496      * Get the namespace part of the action path.
    497      * @param actionPath Full path to action
    498      * @return The namespace part.
    499      */
    500     String getNamespace(String actionPath) {
    501         int idx = actionPath.lastIndexOf('/');
    502         String namespace = "";
    503         if (idx >= 0) {
    504             namespace = actionPath.substring(0, idx);
    505         }
    506         return namespace;
    507     }
    508
    509     /***
    510      * Get the action name part of the action path.
    511      * @param actionPath Full path to action
    512      * @return The action name.
    513      */
    514     String getActionName(String actionPath) {
    515         int idx = actionPath.lastIndexOf('/');
    516         String action = actionPath;
    517         if (idx >= 0) {
    518             action = actionPath.substring(idx + 1);
    519         }
    520         return action;
    521     }
    522
    523     /***
    524      * Returns a Map of all request parameters. This implementation just calls
    525      * {@link PortletRequest#getParameterMap()}.
    526      *
    527      * @param request the PortletRequest object.
    528      * @return a Map of all request parameters.
    529      * @throws IOException if an exception occurs while retrieving the parameter
    530      *         map.
    531      */
    532     protected Map getParameterMap(PortletRequest request) throws IOException {
    533         return new HashMap(request.getParameterMap());
    534     }
    535
    536     /***
    537      * Returns a Map of all request attributes. The default implementation is to
    538      * wrap the request in a {@link RequestMap}. Override this method to
    539      * customize how request attributes are mapped.
    540      *
    541      * @param request the PortletRequest object.
    542      * @return a Map of all request attributes.
    543      */
    544     protected Map getRequestMap(PortletRequest request) {
    545         return new PortletRequestMap(request);
    546     }
    547
    548     /***
    549      * Returns a Map of all session attributes. The default implementation is to
    550      * wrap the reqeust in a {@link SessionMap}. Override this method to
    551      * customize how session attributes are mapped.
    552      *
    553      * @param request the PortletRequest object.
    554      * @return a Map of all session attributes.
    555      */
    556     protected Map getSessionMap(PortletRequest request) {
    557         return new PortletSessionMap(request);
    558     }
    559
    560     /***
    561      * Convenience method to ease testing.
    562      * @param factory
    563      */
    564     protected void setActionProxyFactory(ActionProxyFactory factory) {
    565         this.factory = factory;
    566     }
    567
    568     /***
    569      * Check to see if the action parameter is valid for the current portlet mode. If the portlet
    570      * mode has been changed with the portal widgets, the action name is invalid, since the
    571      * action name belongs to the previous executing portlet mode. If this method evaluates to
    572      * <code>true</code> the <code>default&lt;Mode&gt;Action</code> is used instead.
    573      * @param request The portlet request.
    574      * @return <code>true</code> if the action should be reset.
    575      */
    576     private boolean resetAction(PortletRequest request) {
    577         boolean reset = false;
    578         Map paramMap = request.getParameterMap();
    579         String[] modeParam = (String[]) paramMap.get(MODE_PARAM);
    580         if (modeParam != null && modeParam.length == 1) {
    581             String originatingMode = modeParam[0];
    582             String currentMode = request.getPortletMode().toString();
    583             if (!currentMode.equals(originatingMode)) {
    584                 reset = true;
    585             }
    586         }
    587         return reset;
    588     }
    589
    590     public void destroy() {
    591         if (dispatcherUtils == null) {
    592             LOG.warn("something is seriously wrong, DispatcherUtil is not initialized (null) ");
    593         } else {
    594             dispatcherUtils.cleanup();
    595         }
    596     }
    597
    598     /***
    599      * @param actionMapper the actionMapper to set
    600      */
    601     public void setActionMapper(ActionMapper actionMapper) {
    602         this.actionMapper = actionMapper;
    603     }
    604
    605 }