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