View Javadoc

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