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 }