View Javadoc
1   /*
2    * $Id$
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.struts.config;
22  
23  import org.apache.commons.digester.AbstractObjectCreationFactory;
24  import org.apache.commons.digester.Digester;
25  import org.apache.commons.digester.Rule;
26  import org.apache.commons.digester.RuleSetBase;
27  import org.apache.commons.digester.SetPropertyRule;
28  import org.apache.struts.action.ActionForward;
29  import org.apache.struts.action.ActionMapping;
30  import org.apache.struts.util.RequestUtils;
31  import org.xml.sax.Attributes;
32  
33  /**
34   * <p>The set of Digester rules required to parse a Struts configuration file
35   * (<code>struts-config.xml</code>).</p>
36   *
37   * @version $Rev$ $Date: 2005-08-16 15:53:27 -0400 (Tue, 16 Aug 2005)
38   *          $
39   * @since Struts 1.1
40   */
41  public class ConfigRuleSet extends RuleSetBase {
42      // --------------------------------------------------------- Public Methods
43  
44      /**
45       * <p>Add the set of Rule instances defined in this RuleSet to the
46       * specified <code>Digester</code> instance, associating them with our
47       * namespace URI (if any).  This method should only be called by a
48       * Digester instance.  These rules assume that an instance of
49       * <code>org.apache.struts.config.ModuleConfig</code> is pushed onto the
50       * evaluation stack before parsing begins.</p>
51       *
52       * @param digester Digester instance to which the new Rule instances
53       *                 should be added.
54       */
55      public void addRuleInstances(Digester digester) {
56          ClassLoader cl = digester.getClassLoader();
57  
58          digester.addRule("struts-config/set-property",
59              new BaseConfigSetPropertyRule());
60  
61          digester.addRule("struts-config/action-mappings",
62              new SetActionMappingClassRule());
63  
64          digester.addFactoryCreate("struts-config/action-mappings/action",
65              new ActionMappingFactory(cl));
66          digester.addSetProperties("struts-config/action-mappings/action");
67          digester.addSetNext("struts-config/action-mappings/action",
68              "addActionConfig", "org.apache.struts.config.ActionConfig");
69  
70          digester.addRule("struts-config/action-mappings/action/set-property",
71              new BaseConfigSetPropertyRule());
72  
73          digester.addObjectCreate("struts-config/action-mappings/action/exception",
74              "org.apache.struts.config.ExceptionConfig", "className");
75          digester.addSetProperties(
76              "struts-config/action-mappings/action/exception");
77          digester.addSetNext("struts-config/action-mappings/action/exception",
78              "addExceptionConfig", "org.apache.struts.config.ExceptionConfig");
79  
80          digester.addRule("struts-config/action-mappings/action/exception/set-property",
81              new BaseConfigSetPropertyRule());
82  
83          digester.addFactoryCreate("struts-config/action-mappings/action/forward",
84              new ActionForwardFactory(cl));
85          digester.addSetProperties(
86              "struts-config/action-mappings/action/forward");
87          digester.addSetNext("struts-config/action-mappings/action/forward",
88              "addForwardConfig", "org.apache.struts.config.ForwardConfig");
89  
90          digester.addRule("struts-config/action-mappings/action/forward/set-property",
91              new BaseConfigSetPropertyRule());
92  
93          digester.addObjectCreate("struts-config/controller",
94              "org.apache.struts.config.ControllerConfig", "className");
95          digester.addSetProperties("struts-config/controller");
96          digester.addSetNext("struts-config/controller", "setControllerConfig",
97              "org.apache.struts.config.ControllerConfig");
98  
99          digester.addRule("struts-config/controller/set-property",
100             new BaseConfigSetPropertyRule());
101 
102         digester.addRule("struts-config/form-beans",
103             new SetActionFormBeanClassRule());
104 
105         digester.addFactoryCreate("struts-config/form-beans/form-bean",
106             new ActionFormBeanFactory(cl));
107         digester.addSetProperties("struts-config/form-beans/form-bean");
108         digester.addSetNext("struts-config/form-beans/form-bean",
109             "addFormBeanConfig", "org.apache.struts.config.FormBeanConfig");
110 
111         digester.addObjectCreate("struts-config/form-beans/form-bean/form-property",
112             "org.apache.struts.config.FormPropertyConfig", "className");
113         digester.addSetProperties(
114             "struts-config/form-beans/form-bean/form-property");
115         digester.addSetNext("struts-config/form-beans/form-bean/form-property",
116             "addFormPropertyConfig",
117             "org.apache.struts.config.FormPropertyConfig");
118 
119         digester.addRule("struts-config/form-beans/form-bean/form-property/set-property",
120             new BaseConfigSetPropertyRule());
121 
122         digester.addRule("struts-config/form-beans/form-bean/set-property",
123             new BaseConfigSetPropertyRule());
124 
125         digester.addObjectCreate("struts-config/global-exceptions/exception",
126             "org.apache.struts.config.ExceptionConfig", "className");
127         digester.addSetProperties("struts-config/global-exceptions/exception");
128         digester.addSetNext("struts-config/global-exceptions/exception",
129             "addExceptionConfig", "org.apache.struts.config.ExceptionConfig");
130 
131         digester.addRule("struts-config/global-exceptions/exception/set-property",
132             new BaseConfigSetPropertyRule());
133 
134         digester.addRule("struts-config/global-forwards",
135             new SetActionForwardClassRule());
136 
137         digester.addFactoryCreate("struts-config/global-forwards/forward",
138             new GlobalForwardFactory(cl));
139         digester.addSetProperties("struts-config/global-forwards/forward");
140         digester.addSetNext("struts-config/global-forwards/forward",
141             "addForwardConfig", "org.apache.struts.config.ForwardConfig");
142 
143         digester.addRule("struts-config/global-forwards/forward/set-property",
144             new BaseConfigSetPropertyRule());
145 
146         digester.addObjectCreate("struts-config/message-resources",
147             "org.apache.struts.config.MessageResourcesConfig", "className");
148         digester.addSetProperties("struts-config/message-resources");
149         digester.addSetNext("struts-config/message-resources",
150             "addMessageResourcesConfig",
151             "org.apache.struts.config.MessageResourcesConfig");
152 
153         digester.addRule("struts-config/message-resources/set-property",
154             new BaseConfigSetPropertyRule());
155 
156         digester.addObjectCreate("struts-config/plug-in",
157             "org.apache.struts.config.PlugInConfig");
158         digester.addSetProperties("struts-config/plug-in");
159         digester.addSetNext("struts-config/plug-in", "addPlugInConfig",
160             "org.apache.struts.config.PlugInConfig");
161 
162         digester.addRule("struts-config/plug-in/set-property",
163             new PlugInSetPropertyRule());
164 
165         // PluginConfig does not extend BaseConfig, at least for now.
166     }
167 }
168 
169 
170 /**
171  * <p> Class that records the name and value of a configuration property to be
172  * used in configuring a <code>PlugIn</code> instance when instantiated. </p>
173  */
174 final class PlugInSetPropertyRule extends Rule {
175     public PlugInSetPropertyRule() {
176         super();
177     }
178 
179     public void begin(String namespace, String names, Attributes attributes)
180         throws Exception {
181         PlugInConfig plugInConfig = (PlugInConfig) getDigester().peek();
182 
183         plugInConfig.addProperty(attributes.getValue("property"),
184             attributes.getValue("value"));
185     }
186 }
187 
188 
189 /**
190  * <p> Class that sets the name of the class to use when creating action form
191  * bean instances. The value is set on the object on the top of the stack,
192  * which must be a <code>org.apache.struts.config.ModuleConfig</code>. </p>
193  */
194 final class SetActionFormBeanClassRule extends Rule {
195     public SetActionFormBeanClassRule() {
196         super();
197     }
198 
199     public void begin(String namespace, String name, Attributes attributes)
200         throws Exception {
201         String className = attributes.getValue("type");
202 
203         if (className != null) {
204             ModuleConfig mc = (ModuleConfig) getDigester().peek();
205 
206             mc.setActionFormBeanClass(className);
207         }
208     }
209 }
210 
211 
212 /**
213  * <p> A variant of the standard Digester <code>SetPropertyRule</code>.  If
214  * the element being processed has a "key" attribute, then the value will be
215  * used to call <code>setProperty(key,value)</code> on the object on top of
216  * the stack, which will be assumed to be of type <code>ActionConfig</code>.
217  * Otherwise, the standard <code>SetPropertyRule</code> behavior is invoked,
218  * and the value will be used to set a bean property on the object on top of
219  * the Digester stack. In that case, the element being processed is assumed to
220  * have attributes "property" and "value". </p>
221  */
222 final class BaseConfigSetPropertyRule extends SetPropertyRule {
223     public BaseConfigSetPropertyRule() {
224         super("property", "value");
225     }
226 
227     public void begin(String namespace, String name, Attributes attributes)
228         throws Exception {
229         if (attributes.getIndex("key") == -1) {
230             super.begin(namespace, name, attributes);
231 
232             return;
233         }
234 
235         if (attributes.getIndex("property") != -1) {
236             throw new IllegalArgumentException(
237                 "<set-property> accepts only one of 'key' or 'property' attributes.");
238         }
239 
240         Object topOfStack = getDigester().peek();
241 
242         if (topOfStack instanceof BaseConfig) {
243             BaseConfig config = (BaseConfig) topOfStack;
244 
245             config.setProperty(attributes.getValue("key"),
246                 attributes.getValue("value"));
247         } else {
248             throw new IllegalArgumentException(
249                 "'key' attribute of <set-property> only applicable to subclasses of BaseConfig; "
250                 + "object on top of stack is " + topOfStack + " [key: "
251                 + attributes.getValue("key") + ", value: "
252                 + attributes.getValue("value") + "]");
253         }
254     }
255 }
256 
257 
258 /**
259  * <p> An object creation factory which creates action form bean instances,
260  * taking into account the default class name, which may have been specified
261  * on the parent element and which is made available through the object on the
262  * top of the stack, which must be a <code>org.apache.struts.config.ModuleConfig</code>.
263  * </p>
264  */
265 final class ActionFormBeanFactory extends AbstractObjectCreationFactory {
266     // Digester3: FormBeanConfig
267 
268     private ClassLoader cl;
269 
270     public ActionFormBeanFactory(ClassLoader cl) {
271         super();
272         this.cl = cl;
273     }
274 
275     public FormBeanConfig createObject(Attributes attributes) {
276         // Identify the name of the class to instantiate
277         String className = attributes.getValue("className");
278 
279         if (className == null) {
280             ModuleConfig mc = (ModuleConfig) getDigester().peek();
281 
282             className = mc.getActionFormBeanClass();
283         }
284 
285         // Instantiate the new object and return it
286         FormBeanConfig actionFormBean = null;
287 
288         try {
289             actionFormBean = (FormBeanConfig) RequestUtils.applicationInstance(className, cl);
290         } catch (Exception e) {
291             getDigester().getLogger().error("ActionFormBeanFactory.createObject: ", e);
292         }
293 
294         return actionFormBean;
295     }
296 }
297 
298 
299 /**
300  * <p> Class that sets the name of the class to use when creating action
301  * mapping instances. The value is set on the object on the top of the stack,
302  * which must be a <code>org.apache.struts.config.ModuleConfig</code>. </p>
303  */
304 final class SetActionMappingClassRule extends Rule {
305     public SetActionMappingClassRule() {
306         super();
307     }
308 
309     public void begin(String namespace, String name, Attributes attributes)
310         throws Exception {
311         String className = attributes.getValue("type");
312 
313         if (className != null) {
314             ModuleConfig mc = (ModuleConfig) getDigester().peek();
315 
316             mc.setActionMappingClass(className);
317         }
318     }
319 }
320 
321 
322 /**
323  * <p> An object creation factory which creates action mapping instances,
324  * taking into account the default class name, which may have been specified
325  * on the parent element and which is made available through the object on the
326  * top of the stack, which must be a <code>org.apache.struts.config.ModuleConfig</code>.
327  * </p>
328  */
329 final class ActionMappingFactory extends AbstractObjectCreationFactory {
330     // Digester3: ActionMapping
331 
332     private ClassLoader cl;
333 
334     public ActionMappingFactory(ClassLoader cl) {
335         super();
336         this.cl = cl;
337     }
338 
339     public ActionMapping createObject(Attributes attributes) {
340         // Identify the name of the class to instantiate
341         String className = attributes.getValue("className");
342 
343         if (className == null) {
344             ModuleConfig mc = (ModuleConfig) getDigester().peek();
345 
346             className = mc.getActionMappingClass();
347         }
348 
349         // Instantiate the new object and return it
350         ActionMapping actionMapping = null;
351 
352         try {
353             actionMapping = (ActionMapping) RequestUtils.applicationInstance(className, cl);
354         } catch (Exception e) {
355             getDigester().getLogger().error("ActionMappingFactory.createObject: ", e);
356         }
357 
358         return actionMapping;
359     }
360 }
361 
362 
363 /**
364  * <p> Class that sets the name of the class to use when creating global
365  * forward instances. The value is set on the object on the top of the stack,
366  * which must be a <code>org.apache.struts.config.ModuleConfig</code>. </p>
367  */
368 final class SetActionForwardClassRule extends Rule {
369     public SetActionForwardClassRule() {
370         super();
371     }
372 
373     public void begin(String namespace, String name, Attributes attributes)
374         throws Exception {
375         String className = attributes.getValue("type");
376 
377         if (className != null) {
378             ModuleConfig mc = (ModuleConfig) getDigester().peek();
379 
380             mc.setActionForwardClass(className);
381         }
382     }
383 }
384 
385 
386 /**
387  * <p> An object creation factory which creates global forward instances,
388  * taking into account the default class name, which may have been specified
389  * on the parent element and which is made available through the object on the
390  * top of the stack, which must be a <code>org.apache.struts.config.ModuleConfig</code>.
391  * </p>
392  */
393 final class GlobalForwardFactory extends AbstractObjectCreationFactory {
394     // Digester3: ActionForward
395 
396     private ClassLoader cl;
397 
398     public GlobalForwardFactory(ClassLoader cl) {
399         super();
400         this.cl = cl;
401     }
402 
403     public ActionForward createObject(Attributes attributes) {
404         // Identify the name of the class to instantiate
405         String className = attributes.getValue("className");
406 
407         if (className == null) {
408             ModuleConfig mc = (ModuleConfig) getDigester().peek();
409 
410             className = mc.getActionForwardClass();
411         }
412 
413         // Instantiate the new object and return it
414         ActionForward globalForward = null;
415 
416         try {
417             globalForward = (ActionForward) RequestUtils.applicationInstance(className, cl);
418         } catch (Exception e) {
419             getDigester().getLogger().error("GlobalForwardFactory.createObject: ", e);
420         }
421 
422         return globalForward;
423     }
424 }
425 
426 
427 /**
428  * <p> An object creation factory which creates action forward instances,
429  * taking into account the default class name, which may have been specified
430  * on the parent element and which is made available through the object on the
431  * top of the stack, which must be a <code>org.apache.struts.config.ModuleConfig</code>.
432  * </p>
433  */
434 final class ActionForwardFactory extends AbstractObjectCreationFactory {
435     // Digester3: ActionForward
436 
437     private ClassLoader cl;
438 
439     public ActionForwardFactory(ClassLoader cl) {
440         super();
441         this.cl = cl;
442     }
443 
444     public ActionForward createObject(Attributes attributes) {
445         // Identify the name of the class to instantiate
446         String className = attributes.getValue("className");
447 
448         if (className == null) {
449             ModuleConfig mc = (ModuleConfig) getDigester().peek(1);
450 
451             className = mc.getActionForwardClass();
452         }
453 
454         // Instantiate the new object and return it
455         ActionForward actionForward = null;
456 
457         try {
458             actionForward = (ActionForward) RequestUtils.applicationInstance(className, cl);
459         } catch (Exception e) {
460             getDigester().getLogger().error("ActionForwardFactory.createObject: ", e);
461         }
462 
463         return actionForward;
464     }
465 }