KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > struts > action > ActionServlet


1 /*
2  * $Id: ActionServlet.java 164530 2005-04-25 03:11:07Z niallp $
3  *
4  * Copyright 2000-2005 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 package org.apache.struts.action;
20
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.math.BigDecimal JavaDoc;
24 import java.math.BigInteger JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Enumeration JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.MissingResourceException JavaDoc;
31
32 import javax.servlet.ServletContext JavaDoc;
33 import javax.servlet.ServletException JavaDoc;
34 import javax.servlet.UnavailableException JavaDoc;
35 import javax.servlet.http.HttpServlet JavaDoc;
36 import javax.servlet.http.HttpServletRequest JavaDoc;
37 import javax.servlet.http.HttpServletResponse JavaDoc;
38 import javax.sql.DataSource JavaDoc;
39
40 import org.apache.commons.beanutils.BeanUtils;
41 import org.apache.commons.beanutils.ConvertUtils;
42 import org.apache.commons.beanutils.PropertyUtils;
43 import org.apache.commons.beanutils.converters.BigDecimalConverter;
44 import org.apache.commons.beanutils.converters.BigIntegerConverter;
45 import org.apache.commons.beanutils.converters.BooleanConverter;
46 import org.apache.commons.beanutils.converters.ByteConverter;
47 import org.apache.commons.beanutils.converters.CharacterConverter;
48 import org.apache.commons.beanutils.converters.DoubleConverter;
49 import org.apache.commons.beanutils.converters.FloatConverter;
50 import org.apache.commons.beanutils.converters.IntegerConverter;
51 import org.apache.commons.beanutils.converters.LongConverter;
52 import org.apache.commons.beanutils.converters.ShortConverter;
53 import org.apache.commons.collections.FastHashMap;
54 import org.apache.commons.digester.Digester;
55 import org.apache.commons.digester.RuleSet;
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58 import org.apache.struts.Globals;
59 import org.apache.struts.config.ConfigRuleSet;
60 import org.apache.struts.config.DataSourceConfig;
61 import org.apache.struts.config.FormBeanConfig;
62 import org.apache.struts.config.MessageResourcesConfig;
63 import org.apache.struts.config.ModuleConfig;
64 import org.apache.struts.config.ModuleConfigFactory;
65 import org.apache.struts.config.PlugInConfig;
66 import org.apache.struts.util.MessageResources;
67 import org.apache.struts.util.MessageResourcesFactory;
68 import org.apache.struts.util.ModuleUtils;
69 import org.apache.struts.util.RequestUtils;
70 import org.apache.struts.util.ServletContextWriter;
71 import org.xml.sax.InputSource JavaDoc;
72 import org.xml.sax.SAXException JavaDoc;
73
74 /**
75  * <p><strong>ActionServlet</strong> provides the "controller" in the
76  * Model-View-Controller (MVC) design pattern for web applications that is
77  * commonly known as "Model 2". This nomenclature originated with a
78  * description in the JavaServerPages Specification, version 0.92, and has
79  * persisted ever since (in the absence of a better name).</p>
80  *
81  * <p>Generally, a "Model 2" application is architected as follows:</p>
82  * <ul>
83  * <li>The user interface will generally be created with server pages, which
84  * will not themselves contain any business logic. These pages represent
85  * the "view" component of an MVC architecture.</li>
86  * <li>Forms and hyperlinks in the user interface that require business logic
87  * to be executed will be submitted to a request URI that is mapped to this
88  * servlet.</li>
89  * <li>There can be <b>one</b> instance of this servlet class,
90  * which receives and processes all requests that change the state of
91  * a user's interaction with the application. The servlet delegates the
92  * handling of a request to a {@link RequestProcessor} object. This component
93  * represents the "controller" component of an MVC architecture.</li>
94  * <li>The <code>RequestProcessor</code> selects and invokes an {@link Action} class to perform
95  * the requested business logic, or delegates the response to another resource.</li>
96  * <li>The <code>Action</code> classes can manipulate the state of the application's
97  * interaction with the user, typically by creating or modifying JavaBeans
98  * that are stored as request or session attributes (depending on how long
99  * they need to be available). Such JavaBeans represent the "model"
100  * component of an MVC architecture.</li>
101  * <li>Instead of producing the next page of the user interface directly,
102  * <code>Action</code> classes generally return an {@link ActionForward} to indicate
103  * which resource should handle the response. If the <code>Action</code>
104  * does not return null, the <code>RequestProcessor</code> forwards or
105  * redirects to the specified resource (by utilizing
106  * <code>RequestDispatcher.forward</code> or <code>Response.sendRedirect</code>)
107  * so as to produce the next page of the user interface.</li>
108  * </ul>
109  *
110  * <p>The standard version of <code>RequestsProcessor</code> implements the
111  * following logic for each incoming HTTP request. You can override
112  * some or all of this functionality by subclassing this object and
113  * implementing your own version of the processing.</p>
114  * <ul>
115  * <li>Identify, from the incoming request URI, the substring that will be
116  * used to select an action procedure.</li>
117  * <li>Use this substring to map to the Java class name of the corresponding
118  * action class (an implementation of the <code>Action</code> interface).
119  * </li>
120  * <li>If this is the first request for a particular <code>Action</code> class,
121  * instantiate an instance of that class and cache it for future use.</li>
122  * <li>Optionally populate the properties of an <code>ActionForm</code> bean
123  * associated with this mapping.</li>
124  * <li>Call the <code>execute</code> method of this <code>Action</code> class, passing
125  * on a reference to the mapping that was used, the relevant form-bean
126  * (if any), and the request and the response that were passed to the
127  * controller by the servlet container (thereby providing access to any
128  * specialized properties of the mapping itself as well as to the
129  * ServletContext).
130  * </li>
131  * </ul>
132  *
133  * <p>The standard version of <code>ActionServlet</code> is configured based
134  * on the following servlet initialization parameters, which you will specify
135  * in the web application deployment descriptor (<code>/WEB-INF/web.xml</code>)
136  * for your application. Subclasses that specialize this servlet are free to
137  * define additional initialization parameters. </p>
138  * <ul>
139  * <li><strong>config</strong> - Comma-separated list of context-relative
140  * path(s) to the XML resource(s) containing the configuration information
141  * for the default module. (Multiple files support since Struts 1.1)
142  * [/WEB-INF/struts-config.xml].</li>
143  * <li><strong>config/${module}</strong> - Comma-separated list of
144  * Context-relative path(s) to the XML resource(s)
145  * containing the configuration information for the module that
146  * will use the specified prefix (/${module}). This can be repeated as many
147  * times as required for multiple modules. (Since Struts 1.1)</li>
148  * <li><strong>configFactory</strong> - The Java class name of the
149  * <code>ModuleConfigFactory</code> used to create the implementation of the
150  * <code>ModuleConfig</code> interface.
151  * [org.apache.struts.config.impl.DefaultModuleConfigFactory]
152  * </li>
153  * <li><strong>convertNull</strong> - Force simulation of the Struts 1.0 behavior
154  * when populating forms. If set to true, the numeric Java wrapper class types
155  * (like <code>java.lang.Integer</code>) will default to null (rather than 0).
156  * (Since Struts 1.1) [false] </li>
157  * <li><strong>rulesets</strong> - Comma-delimited list of fully qualified
158  * classnames of additional <code>org.apache.commons.digester.RuleSet</code>
159  * instances that should be added to the <code>Digester</code> that will
160  * be processing <code>struts-config.xml</code> files. By default, only
161  * the <code>RuleSet</code> for the standard configuration elements is
162  * loaded. (Since Struts 1.1)</li>
163  * <li><strong>validating</strong> - Should we use a validating XML parser to
164  * process the configuration file (strongly recommended)? [true]</li>
165  * </ul>
166  *
167  * @version $Rev: 164530 $ $Date: 2005-04-25 04:11:07 +0100 (Mon, 25 Apr 2005) $
168  */

169 public class ActionServlet extends HttpServlet JavaDoc {
170
171
172     // ----------------------------------------------------- Instance Variables
173

174
175     /**
176      * <p>Comma-separated list of context-relative path(s) to our configuration
177      * resource(s) for the default module.</p>
178      */

179     protected String JavaDoc config = "/WEB-INF/struts-config.xml";
180
181
182     /**
183      * <p>The Digester used to produce ModuleConfig objects from a
184      * Struts configuration file.</p>
185      *
186      * @since Struts 1.1
187      */

188     protected Digester configDigester = null;
189
190
191     /**
192      * <p>The flag to request backwards-compatible conversions for form bean
193      * properties of the Java wrapper class types.</p>
194      *
195      * @since Struts 1.1
196      */

197     protected boolean convertNull = false;
198
199
200     /**
201      * <p>The JDBC data sources that has been configured for this module,
202      * if any, keyed by the servlet context attribute under which they are
203      * stored.</p>
204      */

205     protected FastHashMap dataSources = new FastHashMap();
206
207
208     /**
209      * <p>The resources object for our internal resources.</p>
210      */

211     protected MessageResources internal = null;
212
213
214     /**
215      * <p>The Java base name of our internal resources.</p>
216      * @since Struts 1.1
217      */

218     protected String JavaDoc internalName = "org.apache.struts.action.ActionResources";
219
220
221     /**
222      * <p>Commons Logging instance.</p>
223      *
224      * @since Struts 1.1
225      */

226     protected static Log log = LogFactory.getLog(ActionServlet.class);
227
228
229     /**
230      * <p>The <code>RequestProcessor</code> instance we will use to process
231      * all incoming requests.</p>
232      *
233      * @since Struts 1.1
234      */

235     protected RequestProcessor processor = null;
236
237
238     /**
239      * <p>The set of public identifiers, and corresponding resource names, for
240      * the versions of the configuration file DTDs that we know about. There
241      * <strong>MUST</strong> be an even number of Strings in this list!</p>
242      */

243     protected String JavaDoc registrations[] = {
244         "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
245         "/org/apache/struts/resources/struts-config_1_0.dtd",
246         "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",
247         "/org/apache/struts/resources/struts-config_1_1.dtd",
248         "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN",
249         "/org/apache/struts/resources/struts-config_1_2.dtd",
250         "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",
251         "/org/apache/struts/resources/web-app_2_2.dtd",
252         "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
253         "/org/apache/struts/resources/web-app_2_3.dtd"
254     };
255
256
257     /**
258      * <p>The URL pattern to which we are mapped in our web application
259      * deployment descriptor.</p>
260      */

261     protected String JavaDoc servletMapping = null; // :FIXME: - multiples?
262

263
264     /**
265      * <p>The servlet name under which we are registered in our web application
266      * deployment descriptor.</p>
267      */

268     protected String JavaDoc servletName = null;
269
270
271     // ---------------------------------------------------- HttpServlet Methods
272

273
274     /**
275      * <p>Gracefully shut down this controller servlet, releasing any resources
276      * that were allocated at initialization.</p>
277      */

278     public void destroy() {
279
280         if (log.isDebugEnabled()) {
281             log.debug(internal.getMessage("finalizing"));
282         }
283
284         destroyModules();
285         destroyInternal();
286         getServletContext().removeAttribute(Globals.ACTION_SERVLET_KEY);
287
288         // Release our LogFactory and Log instances (if any)
289
ClassLoader JavaDoc classLoader = Thread.currentThread().getContextClassLoader();
290         if (classLoader == null) {
291             classLoader = ActionServlet.class.getClassLoader();
292         }
293         try {
294             LogFactory.release(classLoader);
295         } catch (Throwable JavaDoc t) {
296             ; // Servlet container doesn't have the latest version
297
; // of commons-logging-api.jar installed
298

299             // :FIXME: Why is this dependent on the container's version of commons-logging?
300
// Shouldn't this depend on the version packaged with Struts?
301
/*
302               Reason: LogFactory.release(classLoader); was added as
303               an attempt to investigate the OutOfMemory error reported on Bugzilla #14042.
304               It was committed for version 1.136 by craigmcc
305             */

306         }
307
308         PropertyUtils.clearDescriptors();
309
310     }
311
312
313     /**
314      * <p>Initialize this servlet. Most of the processing has been factored into
315      * support methods so that you can override particular functionality at a
316      * fairly granular level.</p>
317      *
318      * @exception ServletException if we cannot configure ourselves correctly
319      */

320     public void init() throws ServletException JavaDoc {
321
322         // Wraps the entire initialization in a try/catch to better handle
323
// unexpected exceptions and errors to provide better feedback
324
// to the developer
325
try {
326             initInternal();
327             initOther();
328             initServlet();
329     
330             getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
331             initModuleConfigFactory();
332             // Initialize modules as needed
333
ModuleConfig moduleConfig = initModuleConfig("", config);
334             initModuleMessageResources(moduleConfig);
335             initModuleDataSources(moduleConfig);
336             initModulePlugIns(moduleConfig);
337             moduleConfig.freeze();
338     
339             Enumeration JavaDoc names = getServletConfig().getInitParameterNames();
340             while (names.hasMoreElements()) {
341                 String JavaDoc name = (String JavaDoc) names.nextElement();
342                 if (!name.startsWith("config/")) {
343                     continue;
344                 }
345                 String JavaDoc prefix = name.substring(6);
346                 moduleConfig = initModuleConfig
347                     (prefix, getServletConfig().getInitParameter(name));
348                 initModuleMessageResources(moduleConfig);
349                 initModuleDataSources(moduleConfig);
350                 initModulePlugIns(moduleConfig);
351                 moduleConfig.freeze();
352             }
353     
354             this.initModulePrefixes(this.getServletContext());
355     
356             this.destroyConfigDigester();
357         } catch (UnavailableException JavaDoc ex) {
358             throw ex;
359         } catch (Throwable JavaDoc t) {
360
361             // The follow error message is not retrieved from internal message
362
// resources as they may not have been able to have been
363
// initialized
364
log.error("Unable to initialize Struts ActionServlet due to an "
365                 + "unexpected exception or error thrown, so marking the "
366                 + "servlet as unavailable. Most likely, this is due to an "
367                 + "incorrect or missing library dependency.", t);
368             throw new UnavailableException JavaDoc(t.getMessage());
369         }
370     }
371
372     /**
373      * <p>Saves a String[] of module prefixes in the ServletContext under
374      * Globals.MODULE_PREFIXES_KEY. <strong>NOTE</strong> -
375      * the "" prefix for the default module is not included in this list.</p>
376      *
377      * @param context The servlet context.
378      * @since Struts 1.2
379      */

380     protected void initModulePrefixes(ServletContext JavaDoc context) {
381         ArrayList JavaDoc prefixList = new ArrayList JavaDoc();
382
383         Enumeration JavaDoc names = context.getAttributeNames();
384         while (names.hasMoreElements()) {
385             String JavaDoc name = (String JavaDoc) names.nextElement();
386             if (!name.startsWith(Globals.MODULE_KEY)) {
387                 continue;
388             }
389
390             String JavaDoc prefix = name.substring(Globals.MODULE_KEY.length());
391             if (prefix.length() > 0) {
392                 prefixList.add(prefix);
393             }
394         }
395
396         String JavaDoc[] prefixes = (String JavaDoc[]) prefixList.toArray(new String JavaDoc[prefixList.size()]);
397         context.setAttribute(Globals.MODULE_PREFIXES_KEY, prefixes);
398     }
399
400
401     /**
402      * <p>Process an HTTP "GET" request.</p>
403      *
404      * @param request The servlet request we are processing
405      * @param response The servlet response we are creating
406      *
407      * @exception IOException if an input/output error occurs
408      * @exception ServletException if a servlet exception occurs
409      */

410     public void doGet(HttpServletRequest JavaDoc request,
411               HttpServletResponse JavaDoc response)
412         throws IOException JavaDoc, ServletException JavaDoc {
413
414         process(request, response);
415
416     }
417
418
419     /**
420      * <p>Process an HTTP "POST" request.</p>
421      *
422      * @param request The servlet request we are processing
423      * @param response The servlet response we are creating
424      *
425      * @exception IOException if an input/output error occurs
426      * @exception ServletException if a servlet exception occurs
427      */

428     public void doPost(HttpServletRequest JavaDoc request,
429                HttpServletResponse JavaDoc response)
430         throws IOException JavaDoc, ServletException JavaDoc {
431
432         process(request, response);
433
434     }
435
436
437     // --------------------------------------------------------- Public Methods
438

439
440     /**
441      * <p>Remember a servlet mapping from our web application deployment
442      * descriptor, if it is for this servlet.</p>
443      *
444      * @param servletName The name of the servlet being mapped
445      * @param urlPattern The URL pattern to which this servlet is mapped
446      */

447     public void addServletMapping(String JavaDoc servletName, String JavaDoc urlPattern) {
448
449         if (log.isDebugEnabled()) {
450             log.debug("Process servletName=" + servletName +
451                       ", urlPattern=" + urlPattern);
452         }
453         if (servletName == null) {
454             return;
455         }
456         if (servletName.equals(this.servletName)) {
457             this.servletMapping = urlPattern;
458         }
459
460     }
461
462
463     /**
464      * <p>Return the <code>MessageResources</code> instance containing our
465      * internal message strings.</p>
466      *
467      * @since Struts 1.1
468      */

469     public MessageResources getInternal() {
470
471         return (this.internal);
472
473     }
474
475
476     // ------------------------------------------------------ Protected Methods
477

478     /**
479      * <p>Gracefully terminate use of any modules associated with this
480      * application (if any).</p>
481      *
482      * @since Struts 1.1
483      */

484     protected void destroyModules() {
485
486         ArrayList JavaDoc values = new ArrayList JavaDoc();
487         Enumeration JavaDoc names = getServletContext().getAttributeNames();
488         while (names.hasMoreElements()) {
489             values.add(names.nextElement());
490         }
491
492         Iterator JavaDoc keys = values.iterator();
493         while (keys.hasNext()) {
494             String JavaDoc name = (String JavaDoc) keys.next();
495             Object JavaDoc value = getServletContext().getAttribute(name);
496
497             if (!(value instanceof ModuleConfig)) {
498                 continue;
499             }
500
501             ModuleConfig config = (ModuleConfig) value;
502
503             if (this.getProcessorForModule(config) != null) {
504                 this.getProcessorForModule(config).destroy();
505             }
506
507             getServletContext().removeAttribute(name);
508
509             PlugIn plugIns[] =
510                 (PlugIn[]) getServletContext().getAttribute(
511                     Globals.PLUG_INS_KEY + config.getPrefix());
512
513             if (plugIns != null) {
514                 for (int i = 0; i < plugIns.length; i++) {
515                     int j = plugIns.length - (i + 1);
516                     plugIns[j].destroy();
517                 }
518
519                 getServletContext().removeAttribute(
520                     Globals.PLUG_INS_KEY + config.getPrefix());
521             }
522
523         }
524
525     }
526
527
528     /**
529      * <p>Gracefully release any configDigester instance that we have created.</p>
530      *
531      * @since Struts 1.1
532      */

533     protected void destroyConfigDigester() {
534
535         configDigester = null;
536
537     }
538
539
540     /**
541      * <p>Gracefully terminate use of the internal MessageResources.</p>
542      */

543     protected void destroyInternal() {
544
545         internal = null;
546
547     }
548
549     /**
550      * <p>Return the module configuration object for the currently selected
551      * module.</p>
552      *
553      * @param request The servlet request we are processing
554      * @since Struts 1.1
555      */

556     protected ModuleConfig getModuleConfig
557         (HttpServletRequest JavaDoc request) {
558
559         ModuleConfig config = (ModuleConfig)
560             request.getAttribute(Globals.MODULE_KEY);
561         if (config == null) {
562             config = (ModuleConfig)
563                 getServletContext().getAttribute(Globals.MODULE_KEY);
564         }
565         return (config);
566
567     }
568
569
570     /**
571      * <p>Look up and return the {@link RequestProcessor} responsible for the
572      * specified module, creating a new one if necessary.</p>
573      *
574      * @param config The module configuration for which to
575      * acquire and return a RequestProcessor.
576      *
577      * @exception ServletException if we cannot instantiate a RequestProcessor
578      * instance
579      * @since Struts 1.1
580      */

581     protected synchronized RequestProcessor getRequestProcessor(ModuleConfig config)
582         throws ServletException JavaDoc {
583
584         // :FIXME: Document UnavailableException?
585

586         RequestProcessor processor = this.getProcessorForModule(config);
587
588         if (processor == null) {
589             try {
590                 processor =
591                     (RequestProcessor) RequestUtils.applicationInstance(
592                         config.getControllerConfig().getProcessorClass());
593
594             } catch (Exception JavaDoc e) {
595                 throw new UnavailableException JavaDoc(
596                     "Cannot initialize RequestProcessor of class "
597                         + config.getControllerConfig().getProcessorClass()
598                         + ": "
599                         + e);
600             }
601
602             processor.init(this, config);
603
604             String JavaDoc key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
605             getServletContext().setAttribute(key, processor);
606
607         }
608
609         return (processor);
610
611     }
612
613
614     /**
615      * <p>Returns the RequestProcessor for the given module or null if one does not
616      * exist. This method will not create a RequestProcessor.</p>
617      *
618      * @param config The ModuleConfig.
619      */

620     private RequestProcessor getProcessorForModule(ModuleConfig config) {
621         String JavaDoc key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
622         return (RequestProcessor) getServletContext().getAttribute(key);
623     }
624
625
626     /**
627      * <p>Initialize the factory used to create the module configuration.</p>
628      * @since Struts 1.2
629      */

630     protected void initModuleConfigFactory(){
631         String JavaDoc configFactory = getServletConfig().getInitParameter("configFactory");
632         if (configFactory != null) {
633             ModuleConfigFactory.setFactoryClass(configFactory);
634         }
635     }
636
637
638     /**
639      * <p>Initialize the module configuration information for the
640      * specified module.</p>
641      *
642      * @param prefix Module prefix for this module
643      * @param paths Comma-separated list of context-relative resource path(s)
644      * for this modules's configuration resource(s)
645      *
646      * @exception ServletException if initialization cannot be performed
647      * @since Struts 1.1
648      */

649     protected ModuleConfig initModuleConfig(String JavaDoc prefix, String JavaDoc paths)
650         throws ServletException JavaDoc {
651
652         // :FIXME: Document UnavailableException? (Doesn't actually throw anything)
653

654         if (log.isDebugEnabled()) {
655             log.debug(
656                 "Initializing module path '"
657                     + prefix
658                     + "' configuration from '"
659                     + paths
660                     + "'");
661         }
662
663         // Parse the configuration for this module
664
ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
665         ModuleConfig config = factoryObject.createModuleConfig(prefix);
666
667         // Configure the Digester instance we will use
668
Digester digester = initConfigDigester();
669
670         // Process each specified resource path
671
while (paths.length() > 0) {
672             digester.push(config);
673             String JavaDoc path = null;
674             int comma = paths.indexOf(',');
675             if (comma >= 0) {
676                 path = paths.substring(0, comma).trim();
677                 paths = paths.substring(comma + 1);
678             } else {
679                 path = paths.trim();
680                 paths = "";
681             }
682
683             if (path.length() < 1) {
684                 break;
685             }
686
687             this.parseModuleConfigFile(digester, path);
688         }
689
690         getServletContext().setAttribute(
691             Globals.MODULE_KEY + config.getPrefix(),
692             config);
693
694         // Force creation and registration of DynaActionFormClass instances
695
// for all dynamic form beans we wil be using
696
FormBeanConfig fbs[] = config.findFormBeanConfigs();
697         for (int i = 0; i < fbs.length; i++) {
698             if (fbs[i].getDynamic()) {
699                 fbs[i].getDynaActionFormClass();
700             }
701         }
702
703         return config;
704     }
705
706
707     /**
708      * <p>Parses one module config file.</p>
709      *
710      * @param digester Digester instance that does the parsing
711      * @param path The path to the config file to parse.
712      *
713      * @throws UnavailableException if file cannot be read or parsed
714      * @since Struts 1.2
715      */

716     protected void parseModuleConfigFile(Digester digester, String JavaDoc path)
717         throws UnavailableException JavaDoc {
718
719         InputStream JavaDoc input = null;
720         try {
721             URL JavaDoc url = getServletContext().getResource(path);
722
723             // If the config isn't in the servlet context, try the class loader
724
// which allows the config files to be stored in a jar
725
if (url == null) {
726                 url = getClass().getResource(path);
727             }
728             
729             if (url == null) {
730                 String JavaDoc msg = internal.getMessage("configMissing", path);
731                 log.error(msg);
732                 throw new UnavailableException JavaDoc(msg);
733             }
734         
735             InputSource JavaDoc is = new InputSource JavaDoc(url.toExternalForm());
736             input = url.openStream();
737             is.setByteStream(input);
738             digester.parse(is);
739
740         } catch (MalformedURLException JavaDoc e) {
741             handleConfigException(path, e);
742         } catch (IOException JavaDoc e) {
743             handleConfigException(path, e);
744         } catch (SAXException JavaDoc e) {
745             handleConfigException(path, e);
746         } finally {
747             if (input != null) {
748                 try {
749                     input.close();
750                 } catch (IOException JavaDoc e) {
751                     throw new UnavailableException JavaDoc(e.getMessage());
752                 }
753             }
754         }
755     }
756
757
758     /**
759      * <p>Simplifies exception handling in the <code>parseModuleConfigFile</code> method.<p>
760      * @param path
761      * @param e
762      * @throws UnavailableException as a wrapper around Exception
763      */

764     private void handleConfigException(String JavaDoc path, Exception JavaDoc e)
765         throws UnavailableException JavaDoc {
766
767         String JavaDoc msg = internal.getMessage("configParse", path);
768         log.error(msg, e);
769         throw new UnavailableException JavaDoc(msg);
770     }
771
772
773     /**
774      * <p>Initialize the data sources for the specified module.</p>
775      *
776      * @param config ModuleConfig information for this module
777      *
778      * @exception ServletException if initialization cannot be performed
779      * @since Struts 1.1
780      */

781     protected void initModuleDataSources(ModuleConfig config) throws ServletException JavaDoc {
782
783         // :FIXME: Document UnavailableException?
784

785         if (log.isDebugEnabled()) {
786             log.debug("Initializing module path '" + config.getPrefix() +
787                 "' data sources");
788         }
789
790         ServletContextWriter scw =
791             new ServletContextWriter(getServletContext());
792         DataSourceConfig dscs[] = config.findDataSourceConfigs();
793         if (dscs == null) {
794             dscs = new DataSourceConfig[0];
795         }
796
797         dataSources.setFast(false);
798         for (int i = 0; i < dscs.length; i++) {
799             if (log.isDebugEnabled()) {
800                 log.debug("Initializing module path '" + config.getPrefix() +
801                     "' data source '" + dscs[i].getKey() + "'");
802             }
803             DataSource JavaDoc ds = null;
804             try {
805                 ds = (DataSource JavaDoc)
806                     RequestUtils.applicationInstance(dscs[i].getType());
807                 BeanUtils.populate(ds, dscs[i].getProperties());
808                 ds.setLogWriter(scw);
809
810             } catch (Exception JavaDoc e) {
811                 log.error(internal.getMessage("dataSource.init", dscs[i].getKey()), e);
812                 throw new UnavailableException JavaDoc
813                     (internal.getMessage("dataSource.init", dscs[i].getKey()));
814             }
815             getServletContext().setAttribute
816                 (dscs[i].getKey() + config.getPrefix(), ds);
817             dataSources.put(dscs[i].getKey(), ds);
818         }
819
820         dataSources.setFast(true);
821
822     }
823
824
825     /**
826      * <p>Initialize the plug ins for the specified module.</p>
827      *
828      * @param config ModuleConfig information for this module
829      *
830      * @exception ServletException if initialization cannot be performed
831      * @since Struts 1.1
832      */

833     protected void initModulePlugIns
834         (ModuleConfig config) throws ServletException JavaDoc {
835
836         if (log.isDebugEnabled()) {
837             log.debug("Initializing module path '" + config.getPrefix() + "' plug ins");
838         }
839
840         PlugInConfig plugInConfigs[] = config.findPlugInConfigs();
841         PlugIn plugIns[] = new PlugIn[plugInConfigs.length];
842
843         getServletContext().setAttribute(Globals.PLUG_INS_KEY + config.getPrefix(), plugIns);
844         for (int i = 0; i < plugIns.length; i++) {
845             try {
846                 plugIns[i] =
847                     (PlugIn)RequestUtils.applicationInstance(plugInConfigs[i].getClassName());
848                  BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties());
849                   // Pass the current plugIn config object to the PlugIn.
850
// The property is set only if the plugin declares it.
851
// This plugin config object is needed by Tiles
852
try {
853                     PropertyUtils.setProperty(
854                         plugIns[i],
855                         "currentPlugInConfigObject",
856                         plugInConfigs[i]);
857                 } catch (Exception JavaDoc e) {
858                   // FIXME Whenever we fail silently, we must document a valid reason
859
// for doing so. Why should we fail silently if a property can't be set on
860
// the plugin?
861
/**
862                      * Between version 1.138-1.140 cedric made these changes.
863                      * The exceptions are caught to deal with containers applying strict security.
864                      * This was in response to bug #15736
865                      *
866                      * Recommend that we make the currentPlugInConfigObject part of the PlugIn Interface if we can, Rob
867                      */

868                 }
869                 plugIns[i].init(this, config);
870
871             } catch (ServletException JavaDoc e) {
872                 throw e;
873             } catch (Exception JavaDoc e) {
874                 String JavaDoc errMsg =
875                     internal.getMessage(
876                         "plugIn.init",
877                         plugInConfigs[i].getClassName());
878
879                 log(errMsg, e);
880                 throw new UnavailableException JavaDoc(errMsg);
881             }
882         }
883
884     }
885
886
887     /**
888      * <p>Initialize the application <code>MessageResources</code> for the specified
889      * module.</p>
890      *
891      * @param config ModuleConfig information for this module
892      *
893      * @exception ServletException if initialization cannot be performed
894      * @since Struts 1.1
895      */

896     protected void initModuleMessageResources(ModuleConfig config)
897         throws ServletException JavaDoc {
898
899         MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();
900         for (int i = 0; i < mrcs.length; i++) {
901             if ((mrcs[i].getFactory() == null)
902                 || (mrcs[i].getParameter() == null)) {
903                 continue;
904             }
905             if (log.isDebugEnabled()) {
906                 log.debug(
907                     "Initializing module path '"
908                         + config.getPrefix()
909                         + "' message resources from '"
910                         + mrcs[i].getParameter()
911                         + "'");
912             }
913
914             String JavaDoc factory = mrcs[i].getFactory();
915             MessageResourcesFactory.setFactoryClass(factory);
916             MessageResourcesFactory factoryObject =
917                 MessageResourcesFactory.createFactory();
918
919             MessageResources resources =
920                 factoryObject.createResources(mrcs[i].getParameter());
921             resources.setReturnNull(mrcs[i].getNull());
922             getServletContext().setAttribute(
923                 mrcs[i].getKey() + config.getPrefix(),
924                 resources);
925         }
926
927     }
928
929
930     /**
931      * <p>Create (if needed) and return a new <code>Digester</code>
932      * instance that has been initialized to process Struts module
933      * configuration files and configure a corresponding <code>ModuleConfig</code>
934      * object (which must be pushed on to the evaluation stack before parsing
935      * begins).</p>
936      *
937      * @exception ServletException if a Digester cannot be configured
938      * @since Struts 1.1
939      */

940     protected Digester initConfigDigester() throws ServletException JavaDoc {
941
942         // :FIXME: Where can ServletException be thrown?
943

944         // Do we have an existing instance?
945
if (configDigester != null) {
946             return (configDigester);
947         }
948
949         // Create a new Digester instance with standard capabilities
950
configDigester = new Digester();
951         configDigester.setNamespaceAware(true);
952         configDigester.setValidating(this.isValidating());
953         configDigester.setUseContextClassLoader(true);
954         configDigester.addRuleSet(new ConfigRuleSet());
955
956         for (int i = 0; i < registrations.length; i += 2) {
957             URL JavaDoc url = this.getClass().getResource(registrations[i+1]);
958             if (url != null) {
959                 configDigester.register(registrations[i], url.toString());
960             }
961         }
962
963         this.addRuleSets();
964
965         // Return the completely configured Digester instance
966
return (configDigester);
967     }
968
969
970     /**
971      * <p>Add any custom RuleSet instances to configDigester that have
972      * been specified in the <code>rulesets</code> init parameter.</p>
973      *
974      * @throws ServletException
975      */

976     private void addRuleSets() throws ServletException JavaDoc {
977
978         String JavaDoc rulesets = getServletConfig().getInitParameter("rulesets");
979         if (rulesets == null) {
980             rulesets = "";
981         }
982
983         rulesets = rulesets.trim();
984         String JavaDoc ruleset = null;
985         while (rulesets.length() > 0) {
986             int comma = rulesets.indexOf(",");
987             if (comma < 0) {
988                 ruleset = rulesets.trim();
989                 rulesets = "";
990             } else {
991                 ruleset = rulesets.substring(0, comma).trim();
992                 rulesets = rulesets.substring(comma + 1).trim();
993             }
994
995             if (log.isDebugEnabled()) {
996                 log.debug("Configuring custom Digester Ruleset of type " + ruleset);
997             }
998
999             try {
1000                RuleSet instance = (RuleSet) RequestUtils.applicationInstance(ruleset);
1001                this.configDigester.addRuleSet(instance);
1002            } catch (Exception JavaDoc e) {
1003                log.error("Exception configuring custom Digester RuleSet", e);
1004                throw new ServletException JavaDoc(e);
1005            }
1006        }
1007    }
1008
1009
1010    /**
1011     * <p>Check the status of the <code>validating</code> initialization parameter.</p>
1012     *
1013     * @return true if the module Digester should validate.
1014     */

1015    private boolean isValidating() {
1016
1017        boolean validating = true;
1018        String JavaDoc value = getServletConfig().getInitParameter("validating");
1019
1020        if ("false".equalsIgnoreCase(value)
1021            || "no".equalsIgnoreCase(value)
1022            || "n".equalsIgnoreCase(value)
1023            || "0".equalsIgnoreCase(value)) {
1024
1025            validating = false;
1026        }
1027
1028        return validating;
1029    }
1030
1031
1032
1033    /**
1034     * <p>Initialize our internal MessageResources bundle.</p>
1035     *
1036     * @exception ServletException if we cannot initialize these resources
1037     */

1038    protected void initInternal() throws ServletException JavaDoc {
1039
1040        // :FIXME: Document UnavailableException
1041

1042        try {
1043            internal = MessageResources.getMessageResources(internalName);
1044        } catch (MissingResourceException JavaDoc e) {
1045            log.error("Cannot load internal resources from '" + internalName + "'",
1046                e);
1047            throw new UnavailableException JavaDoc
1048                ("Cannot load internal resources from '" + internalName + "'");
1049        }
1050
1051    }
1052
1053
1054    /**
1055     * <p>Initialize other global characteristics of the controller servlet.</p>
1056     *
1057     * @exception ServletException if we cannot initialize these resources
1058     */

1059    protected void initOther() throws ServletException JavaDoc {
1060
1061        String JavaDoc value = null;
1062        value = getServletConfig().getInitParameter("config");
1063        if (value != null) {
1064            config = value;
1065        }
1066
1067        // Backwards compatibility for form beans of Java wrapper classes
1068
// Set to true for strict Struts 1.0 compatibility
1069
value = getServletConfig().getInitParameter("convertNull");
1070        if ("true".equalsIgnoreCase(value)
1071            || "yes".equalsIgnoreCase(value)
1072            || "on".equalsIgnoreCase(value)
1073            || "y".equalsIgnoreCase(value)
1074            || "1".equalsIgnoreCase(value)) {
1075
1076            convertNull = true;
1077        }
1078
1079        if (convertNull) {
1080            ConvertUtils.deregister();
1081            ConvertUtils.register(new BigDecimalConverter(null), BigDecimal JavaDoc.class);
1082            ConvertUtils.register(new BigIntegerConverter(null), BigInteger JavaDoc.class);
1083            ConvertUtils.register(new BooleanConverter(null), Boolean JavaDoc.class);
1084            ConvertUtils.register(new ByteConverter(null), Byte JavaDoc.class);
1085            ConvertUtils.register(new CharacterConverter(null), Character JavaDoc.class);
1086            ConvertUtils.register(new DoubleConverter(null), Double JavaDoc.class);
1087            ConvertUtils.register(new FloatConverter(null), Float JavaDoc.class);
1088            ConvertUtils.register(new IntegerConverter(null), Integer JavaDoc.class);
1089            ConvertUtils.register(new LongConverter(null), Long JavaDoc.class);
1090            ConvertUtils.register(new ShortConverter(null), Short JavaDoc.class);
1091        }
1092
1093    }
1094
1095
1096    /**
1097     * <p>Initialize the servlet mapping under which our controller servlet
1098     * is being accessed. This will be used in the <code>&html:form&gt;</code>
1099     * tag to generate correct destination URLs for form submissions.</p>
1100     *
1101     * @throws ServletException if error happens while scanning web.xml
1102     */

1103    protected void initServlet() throws ServletException JavaDoc {
1104
1105        // Remember our servlet name
1106
this.servletName = getServletConfig().getServletName();
1107
1108        // Prepare a Digester to scan the web application deployment descriptor
1109
Digester digester = new Digester();
1110        digester.push(this);
1111        digester.setNamespaceAware(true);
1112        digester.setValidating(false);
1113
1114        // Register our local copy of the DTDs that we can find
1115
for (int i = 0; i < registrations.length; i += 2) {
1116            URL JavaDoc url = this.getClass().getResource(registrations[i+1]);
1117            if (url != null) {
1118                digester.register(registrations[i], url.toString());
1119            }
1120        }
1121
1122        // Configure the processing rules that we need
1123
digester.addCallMethod("web-app/servlet-mapping",
1124                               "addServletMapping", 2);
1125        digester.addCallParam("web-app/servlet-mapping/servlet-name", 0);
1126        digester.addCallParam("web-app/servlet-mapping/url-pattern", 1);
1127
1128        // Process the web application deployment descriptor
1129
if (log.isDebugEnabled()) {
1130            log.debug("Scanning web.xml for controller servlet mapping");
1131        }
1132
1133        InputStream JavaDoc input =
1134            getServletContext().getResourceAsStream("/WEB-INF/web.xml");
1135
1136        if (input == null) {
1137            log.error(internal.getMessage("configWebXml"));
1138            throw new ServletException JavaDoc(internal.getMessage("configWebXml"));
1139        }
1140
1141        try {
1142            digester.parse(input);
1143
1144        } catch (IOException JavaDoc e) {
1145            log.error(internal.getMessage("configWebXml"), e);
1146            throw new ServletException JavaDoc(e);
1147
1148        } catch (SAXException JavaDoc e) {
1149            log.error(internal.getMessage("configWebXml"), e);
1150            throw new ServletException JavaDoc(e);
1151
1152        } finally {
1153            try {
1154                input.close();
1155            } catch (IOException JavaDoc e) {
1156                log.error(internal.getMessage("configWebXml"), e);
1157                throw new ServletException JavaDoc(e);
1158            }
1159        }
1160
1161        // Record a servlet context attribute (if appropriate)
1162
if (log.isDebugEnabled()) {
1163            log.debug("Mapping for servlet '" + servletName + "' = '" +
1164                servletMapping + "'");
1165        }
1166
1167        if (servletMapping != null) {
1168            getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);
1169        }
1170
1171    }
1172
1173
1174    /**
1175     * <p>Perform the standard request processing for this request, and create
1176     * the corresponding response.</p>
1177     *
1178     * @param request The servlet request we are processing
1179     * @param response The servlet response we are creating
1180     *
1181     * @exception IOException if an input/output error occurs
1182     * @exception ServletException if a servlet exception is thrown
1183     */

1184    protected void process(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
1185        throws IOException JavaDoc, ServletException JavaDoc {
1186
1187        ModuleUtils.getInstance().selectModule(request, getServletContext());
1188        ModuleConfig config = getModuleConfig(request);
1189
1190        RequestProcessor processor = getProcessorForModule(config);
1191        if (processor == null) {
1192           processor = getRequestProcessor(config);
1193        }
1194        processor.process(request, response);
1195
1196    }
1197
1198}
1199
Popular Tags