1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.config.impl;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.struts.config.ActionConfig;
23 import org.apache.struts.config.ActionConfigMatcher;
24 import org.apache.struts.config.BaseConfig;
25 import org.apache.struts.config.ControllerConfig;
26 import org.apache.struts.config.ExceptionConfig;
27 import org.apache.struts.config.FormBeanConfig;
28 import org.apache.struts.config.ForwardConfig;
29 import org.apache.struts.config.MessageResourcesConfig;
30 import org.apache.struts.config.ModuleConfig;
31 import org.apache.struts.config.PlugInConfig;
32
33 import java.io.Serializable;
34
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38
39 /***
40 * <p>The collection of static configuration information that describes a
41 * Struts-based module. Multiple modules are identified by a <em>prefix</em>
42 * at the beginning of the context relative portion of the request URI. If no
43 * module prefix can be matched, the default configuration (with a prefix
44 * equal to a zero-length string) is selected, which is elegantly backwards
45 * compatible with the previous Struts behavior that only supported one
46 * module.</p>
47 *
48 * @version $Rev: 421119 $ $Date: 2005-12-31 03:57:16 -0500 (Sat, 31 Dec 2005)
49 * $
50 * @since Struts 1.1
51 */
52 public class ModuleConfigImpl extends BaseConfig implements Serializable,
53 ModuleConfig {
54 /***
55 * <p>Commons Logging instance. </p>
56 */
57 protected static Log log = LogFactory.getLog(ModuleConfigImpl.class);
58
59
60
61
62 /***
63 * <p>The set of action configurations for this module, if any, keyed by
64 * the <code>path</code> property.</p>
65 */
66 protected HashMap actionConfigs = null;
67
68 /***
69 * <p>The set of action configurations for this module, if any, listed in
70 * the order in which they are added.</p>
71 */
72 protected List actionConfigList = null;
73
74 /***
75 * <p>The set of exception handling configurations for this module, if
76 * any, keyed by the <code>type</code> property.</p>
77 */
78 protected HashMap exceptions = null;
79
80 /***
81 * <p>The set of form bean configurations for this module, if any, keyed
82 * by the <code>name</code> property.</p>
83 */
84 protected HashMap formBeans = null;
85
86 /***
87 * <p>The set of global forward configurations for this module, if any,
88 * keyed by the <code>name</code> property.</p>
89 */
90 protected HashMap forwards = null;
91
92 /***
93 * <p>The set of message resources configurations for this module, if any,
94 * keyed by the <code>key</code> property.</p>
95 */
96 protected HashMap messageResources = null;
97
98 /***
99 * <p>The set of configured plug-in Actions for this module, if any, in
100 * the order they were declared and configured.</p>
101 */
102 protected ArrayList plugIns = null;
103
104 /***
105 * <p>The controller configuration object for this module.</p>
106 */
107 protected ControllerConfig controllerConfig = null;
108
109 /***
110 * <p>The prefix of the context-relative portion of the request URI, used
111 * to select this configuration versus others supported by the controller
112 * servlet. A configuration with a prefix of a zero-length String is the
113 * default configuration for this web module.</p>
114 */
115 protected String prefix = null;
116
117 /***
118 * <p>The default class name to be used when creating action form bean
119 * instances.</p>
120 */
121 protected String actionFormBeanClass =
122 "org.apache.struts.action.ActionFormBean";
123
124 /***
125 * The default class name to be used when creating action mapping
126 * instances.
127 */
128 protected String actionMappingClass =
129 "org.apache.struts.action.ActionMapping";
130
131 /***
132 * The default class name to be used when creating action forward
133 * instances.
134 */
135 protected String actionForwardClass =
136 "org.apache.struts.action.ActionForward";
137
138 /***
139 * <p>Matches action config paths against compiled wildcard patterns</p>
140 */
141 protected ActionConfigMatcher matcher = null;
142
143 /***
144 * <p>Constructor for ModuleConfigImpl. Assumes default
145 * configuration.</p>
146 *
147 * @since Struts 1.2.8
148 */
149 public ModuleConfigImpl() {
150 this("");
151 }
152
153 /***
154 * <p>Construct an ModuleConfigImpl object according to the specified
155 * parameter values.</p>
156 *
157 * @param prefix Context-relative URI prefix for this module
158 */
159 public ModuleConfigImpl(String prefix) {
160 super();
161 this.prefix = prefix;
162 this.actionConfigs = new HashMap();
163 this.actionConfigList = new ArrayList();
164 this.actionFormBeanClass = "org.apache.struts.action.ActionFormBean";
165 this.actionMappingClass = "org.apache.struts.action.ActionMapping";
166 this.actionForwardClass = "org.apache.struts.action.ActionForward";
167 this.configured = false;
168 this.controllerConfig = null;
169 this.exceptions = new HashMap();
170 this.formBeans = new HashMap();
171 this.forwards = new HashMap();
172 this.messageResources = new HashMap();
173 this.plugIns = new ArrayList();
174 }
175
176
177
178 /***
179 * </p> Has this module been completely configured yet. Once this flag
180 * has been set, any attempt to modify the configuration will return an
181 * IllegalStateException.</p>
182 */
183 public boolean getConfigured() {
184 return (this.configured);
185 }
186
187 /***
188 * <p>The controller configuration object for this module.</p>
189 */
190 public ControllerConfig getControllerConfig() {
191 if (this.controllerConfig == null) {
192 this.controllerConfig = new ControllerConfig();
193 }
194
195 return (this.controllerConfig);
196 }
197
198 /***
199 * <p>The controller configuration object for this module.</p>
200 *
201 * @param cc The controller configuration object for this module.
202 */
203 public void setControllerConfig(ControllerConfig cc) {
204 throwIfConfigured();
205 this.controllerConfig = cc;
206 }
207
208 /***
209 * <p>The prefix of the context-relative portion of the request URI, used
210 * to select this configuration versus others supported by the controller
211 * servlet. A configuration with a prefix of a zero-length String is the
212 * default configuration for this web module.</p>
213 */
214 public String getPrefix() {
215 return (this.prefix);
216 }
217
218 /***
219 * <p>The prefix of the context-relative portion of the request URI, used
220 * to select this configuration versus others supported by the controller
221 * servlet. A configuration with a prefix of a zero-length String is the
222 * default configuration for this web module.</p>
223 */
224 public void setPrefix(String prefix) {
225 throwIfConfigured();
226 this.prefix = prefix;
227 }
228
229 /***
230 * <p>The default class name to be used when creating action form bean
231 * instances.</p>
232 */
233 public String getActionFormBeanClass() {
234 return this.actionFormBeanClass;
235 }
236
237 /***
238 * <p>The default class name to be used when creating action form bean
239 * instances.</p>
240 *
241 * @param actionFormBeanClass default class name to be used when creating
242 * action form bean instances.
243 */
244 public void setActionFormBeanClass(String actionFormBeanClass) {
245 this.actionFormBeanClass = actionFormBeanClass;
246 }
247
248 /***
249 * <p>The default class name to be used when creating action mapping
250 * instances.</p>
251 */
252 public String getActionMappingClass() {
253 return this.actionMappingClass;
254 }
255
256 /***
257 * <p> The default class name to be used when creating action mapping
258 * instances. </p>
259 *
260 * @param actionMappingClass default class name to be used when creating
261 * action mapping instances.
262 */
263 public void setActionMappingClass(String actionMappingClass) {
264 this.actionMappingClass = actionMappingClass;
265 }
266
267 /***
268 * </p> Ad d a new <code>ActionConfig</code> instance to the set
269 * associated with this module. </p>
270 *
271 * @param config The new configuration instance to be added
272 * @throws IllegalStateException if this module configuration has been
273 * frozen
274 */
275 public void addActionConfig(ActionConfig config) {
276 throwIfConfigured();
277 config.setModuleConfig(this);
278
279 String key = config.getPath();
280
281 if (actionConfigs.containsKey(key)) {
282 log.warn("Overriding ActionConfig of path " + key);
283 }
284
285 actionConfigs.put(key, config);
286 actionConfigList.add(config);
287 }
288
289 /***
290 * <p> Add a new <code>ExceptionConfig</code> instance to the set
291 * associated with this module. </p>
292 *
293 * @param config The new configuration instance to be added
294 * @throws IllegalStateException if this module configuration has been
295 * frozen
296 */
297 public void addExceptionConfig(ExceptionConfig config) {
298 throwIfConfigured();
299
300 String key = config.getType();
301
302 if (exceptions.containsKey(key)) {
303 log.warn("Overriding ExceptionConfig of type " + key);
304 }
305
306 exceptions.put(key, config);
307 }
308
309 /***
310 * <p> Add a new <code>FormBeanConfig</code> instance to the set
311 * associated with this module. </p>
312 *
313 * @param config The new configuration instance to be added
314 * @throws IllegalStateException if this module configuration has been
315 * frozen
316 */
317 public void addFormBeanConfig(FormBeanConfig config) {
318 throwIfConfigured();
319
320 String key = config.getName();
321
322 if (formBeans.containsKey(key)) {
323 log.warn("Overriding ActionForm of name " + key);
324 }
325
326 formBeans.put(key, config);
327 }
328
329 /***
330 * <p> The default class name to be used when creating action forward
331 * instances. </p>
332 */
333 public String getActionForwardClass() {
334 return this.actionForwardClass;
335 }
336
337 /***
338 * <p> The default class name to be used when creating action forward
339 * instances. </p>
340 *
341 * @param actionForwardClass default class name to be used when creating
342 * action forward instances.
343 */
344 public void setActionForwardClass(String actionForwardClass) {
345 this.actionForwardClass = actionForwardClass;
346 }
347
348 /***
349 * <p> Add a new <code>ForwardConfig</code> instance to the set of global
350 * forwards associated with this module. </p>
351 *
352 * @param config The new configuration instance to be added
353 * @throws IllegalStateException if this module configuration has been
354 * frozen
355 */
356 public void addForwardConfig(ForwardConfig config) {
357 throwIfConfigured();
358
359 String key = config.getName();
360
361 if (forwards.containsKey(key)) {
362 log.warn("Overriding global ActionForward of name " + key);
363 }
364
365 forwards.put(key, config);
366 }
367
368 /***
369 * <p> Add a new <code>MessageResourcesConfig</code> instance to the set
370 * associated with this module. </p>
371 *
372 * @param config The new configuration instance to be added
373 * @throws IllegalStateException if this module configuration has been
374 * frozen
375 */
376 public void addMessageResourcesConfig(MessageResourcesConfig config) {
377 throwIfConfigured();
378
379 String key = config.getKey();
380
381 if (messageResources.containsKey(key)) {
382 log.warn("Overriding MessageResources bundle of key " + key);
383 }
384
385 messageResources.put(key, config);
386 }
387
388 /***
389 * <p> Add a newly configured {@link org.apache.struts.config.PlugInConfig}
390 * instance to the set of plug-in Actions for this module. </p>
391 *
392 * @param plugInConfig The new configuration instance to be added
393 */
394 public void addPlugInConfig(PlugInConfig plugInConfig) {
395 throwIfConfigured();
396 plugIns.add(plugInConfig);
397 }
398
399 /***
400 * <p> Return the action configuration for the specified path, first
401 * looking a direct match, then if none found, a wildcard pattern match;
402 * otherwise return <code>null</code>. </p>
403 *
404 * @param path Path of the action configuration to return
405 */
406 public ActionConfig findActionConfig(String path) {
407 ActionConfig config = (ActionConfig) actionConfigs.get(path);
408
409
410
411 if ((config == null) && (matcher != null)) {
412 config = matcher.match(path);
413 }
414
415 return config;
416 }
417
418 /***
419 * <p> Return the action configurations for this module. If there are
420 * none, a zero-length array is returned. </p>
421 */
422 public ActionConfig[] findActionConfigs() {
423 ActionConfig[] results = new ActionConfig[actionConfigList.size()];
424
425 return ((ActionConfig[]) actionConfigList.toArray(results));
426 }
427
428 /***
429 * <p> Return the exception configuration for the specified type, if any;
430 * otherwise return <code>null</code>. </p>
431 *
432 * @param type Exception class name to find a configuration for
433 */
434 public ExceptionConfig findExceptionConfig(String type) {
435 return ((ExceptionConfig) exceptions.get(type));
436 }
437
438 /***
439 * <p>Find and return the <code>ExceptionConfig</code> instance defining
440 * how <code>Exceptions</code> of the specified type should be handled.
441 *
442 * <p>In original Struts usage, this was only available in
443 * <code>ActionConfig</code>, but there are cases when an exception could
444 * be thrown before an <code>ActionConfig</code> has been identified,
445 * where global exception handlers may still be pertinent.</p>
446 *
447 * <p>TODO: Look for a way to share this logic with
448 * <code>ActionConfig</code>, although there are subtle differences, and
449 * it certainly doesn't seem like it should be done with inheritance.</p>
450 *
451 * @param type Exception class for which to find a handler
452 * @since Struts 1.3.0
453 */
454 public ExceptionConfig findException(Class type) {
455
456 ExceptionConfig config = null;
457
458 while (true) {
459
460 String name = type.getName();
461
462 log.debug("findException: look locally for " + name);
463 config = findExceptionConfig(name);
464
465 if (config != null) {
466 return (config);
467 }
468
469
470 type = type.getSuperclass();
471
472 if (type == null) {
473 break;
474 }
475 }
476
477 return (null);
478 }
479
480 /***
481 * <p> Return the exception configurations for this module. If there are
482 * none, a zero-length array is returned. </p>
483 */
484 public ExceptionConfig[] findExceptionConfigs() {
485 ExceptionConfig[] results = new ExceptionConfig[exceptions.size()];
486
487 return ((ExceptionConfig[]) exceptions.values().toArray(results));
488 }
489
490 /***
491 * <p> Return the form bean configuration for the specified key, if any;
492 * otherwise return <code>null</code>. </p>
493 *
494 * @param name Name of the form bean configuration to return
495 */
496 public FormBeanConfig findFormBeanConfig(String name) {
497 return ((FormBeanConfig) formBeans.get(name));
498 }
499
500 /***
501 * <p> Return the form bean configurations for this module. If there are
502 * none, a zero-length array is returned. </p>
503 */
504 public FormBeanConfig[] findFormBeanConfigs() {
505 FormBeanConfig[] results = new FormBeanConfig[formBeans.size()];
506
507 return ((FormBeanConfig[]) formBeans.values().toArray(results));
508 }
509
510 /***
511 * <p> Return the forward configuration for the specified key, if any;
512 * otherwise return <code>null</code>. </p>
513 *
514 * @param name Name of the forward configuration to return
515 */
516 public ForwardConfig findForwardConfig(String name) {
517 return ((ForwardConfig) forwards.get(name));
518 }
519
520 /***
521 * <p> Return the form bean configurations for this module. If there are
522 * none, a zero-length array is returned. </p>
523 */
524 public ForwardConfig[] findForwardConfigs() {
525 ForwardConfig[] results = new ForwardConfig[forwards.size()];
526
527 return ((ForwardConfig[]) forwards.values().toArray(results));
528 }
529
530 /***
531 * <p> Return the message resources configuration for the specified key,
532 * if any; otherwise return <code>null</code>. </p>
533 *
534 * @param key Key of the data source configuration to return
535 */
536 public MessageResourcesConfig findMessageResourcesConfig(String key) {
537 return ((MessageResourcesConfig) messageResources.get(key));
538 }
539
540 /***
541 * <p> Return the message resources configurations for this module. If
542 * there are none, a zero-length array is returned. </p>
543 */
544 public MessageResourcesConfig[] findMessageResourcesConfigs() {
545 MessageResourcesConfig[] results =
546 new MessageResourcesConfig[messageResources.size()];
547
548 return ((MessageResourcesConfig[]) messageResources.values().toArray(results));
549 }
550
551 /***
552 * <p> Return the configured plug-in actions for this module. If there
553 * are none, a zero-length array is returned. </p>
554 */
555 public PlugInConfig[] findPlugInConfigs() {
556 PlugInConfig[] results = new PlugInConfig[plugIns.size()];
557
558 return ((PlugInConfig[]) plugIns.toArray(results));
559 }
560
561 /***
562 * <p> Freeze the configuration of this module. After this method
563 * returns, any attempt to modify the configuration will return an
564 * IllegalStateException. </p>
565 */
566 public void freeze() {
567 super.freeze();
568
569 ActionConfig[] aconfigs = findActionConfigs();
570
571 for (int i = 0; i < aconfigs.length; i++) {
572 aconfigs[i].freeze();
573 }
574
575 matcher = new ActionConfigMatcher(aconfigs);
576
577 getControllerConfig().freeze();
578
579 ExceptionConfig[] econfigs = findExceptionConfigs();
580
581 for (int i = 0; i < econfigs.length; i++) {
582 econfigs[i].freeze();
583 }
584
585 FormBeanConfig[] fbconfigs = findFormBeanConfigs();
586
587 for (int i = 0; i < fbconfigs.length; i++) {
588 fbconfigs[i].freeze();
589 }
590
591 ForwardConfig[] fconfigs = findForwardConfigs();
592
593 for (int i = 0; i < fconfigs.length; i++) {
594 fconfigs[i].freeze();
595 }
596
597 MessageResourcesConfig[] mrconfigs = findMessageResourcesConfigs();
598
599 for (int i = 0; i < mrconfigs.length; i++) {
600 mrconfigs[i].freeze();
601 }
602
603 PlugInConfig[] piconfigs = findPlugInConfigs();
604
605 for (int i = 0; i < piconfigs.length; i++) {
606 piconfigs[i].freeze();
607 }
608 }
609
610 /***
611 * <p> Remove the specified action configuration instance. </p>
612 *
613 * @param config ActionConfig instance to be removed
614 * @throws IllegalStateException if this module configuration has been
615 * frozen
616 */
617 public void removeActionConfig(ActionConfig config) {
618 throwIfConfigured();
619 config.setModuleConfig(null);
620 actionConfigs.remove(config.getPath());
621 actionConfigList.remove(config);
622 }
623
624 /***
625 * <p> Remove the specified exception configuration instance. </p>
626 *
627 * @param config ActionConfig instance to be removed
628 * @throws IllegalStateException if this module configuration has been
629 * frozen
630 */
631 public void removeExceptionConfig(ExceptionConfig config) {
632 throwIfConfigured();
633 exceptions.remove(config.getType());
634 }
635
636 /***
637 * <p> Remove the specified form bean configuration instance. </p>
638 *
639 * @param config FormBeanConfig instance to be removed
640 * @throws IllegalStateException if this module configuration has been
641 * frozen
642 */
643 public void removeFormBeanConfig(FormBeanConfig config) {
644 throwIfConfigured();
645 formBeans.remove(config.getName());
646 }
647
648 /***
649 * <p> Remove the specified forward configuration instance. </p>
650 *
651 * @param config ForwardConfig instance to be removed
652 * @throws IllegalStateException if this module configuration has been
653 * frozen
654 */
655 public void removeForwardConfig(ForwardConfig config) {
656 throwIfConfigured();
657 forwards.remove(config.getName());
658 }
659
660 /***
661 * <p> Remove the specified message resources configuration instance.
662 * </p>
663 *
664 * @param config MessageResourcesConfig instance to be removed
665 * @throws IllegalStateException if this module configuration has been
666 * frozen
667 */
668 public void removeMessageResourcesConfig(MessageResourcesConfig config) {
669 throwIfConfigured();
670 messageResources.remove(config.getKey());
671 }
672 }