1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts.config;
19
20 import org.apache.commons.beanutils.BeanUtils;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.struts.util.RequestUtils;
24
25 import java.lang.reflect.InvocationTargetException;
26
27 import java.util.ArrayList;
28 import java.util.HashMap;
29
30 /***
31 * <p>A JavaBean representing the configuration information of an
32 * <code><action></code> element from a Struts module configuration
33 * file.</p>
34 *
35 * @version $Rev: 421119 $ $Date: 2005-08-06 04:12:10 -0400 (Sat, 06 Aug 2005)
36 * $
37 * @since Struts 1.1
38 */
39 public class ActionConfig extends BaseConfig {
40 private static final Log log = LogFactory.getLog(ActionConfig.class);
41
42
43
44 /***
45 * <p> The set of exception handling configurations for this action, if
46 * any, keyed by the <code>type</code> property. </p>
47 */
48 protected HashMap exceptions = new HashMap();
49
50 /***
51 * <p> The set of local forward configurations for this action, if any,
52 * keyed by the <code>name</code> property. </p>
53 */
54 protected HashMap forwards = new HashMap();
55
56
57
58 /***
59 * <p> The module configuration with which we are associated. </p>
60 */
61 protected ModuleConfig moduleConfig = null;
62
63 /***
64 * <p> The request-scope or session-scope attribute name under which our
65 * form bean is accessed, if it is different from the form bean's
66 * specified <code>name</code>. </p>
67 */
68 protected String attribute = null;
69
70 /***
71 * <p>The path of the ActionConfig that this object should inherit
72 * properties from.</p> </p>
73 */
74 protected String inherit = null;
75
76 /***
77 * <p>Can this Action be cancelled? [false]</p> <p> By default, when an
78 * Action is cancelled, validation is bypassed and the Action should not
79 * execute the business operation. If a request tries to cancel an Action
80 * when cancellable is not set, a "InvalidCancelException" is thrown.
81 * </p>
82 */
83 protected boolean cancellable = false;
84
85 /***
86 * <p> Have the inheritance values for this class been applied?</p>
87 */
88 protected boolean extensionProcessed = false;
89
90 /***
91 * <p> Context-relative path of the web application resource that will
92 * process this request via RequestDispatcher.forward(), instead of
93 * instantiating and calling the <code>Action</code> class specified by
94 * "type". Exactly one of <code>forward</code>, <code>include</code>, or
95 * <code>type</code> must be specified. </p>
96 */
97 protected String forward = null;
98
99 /***
100 * <p> Context-relative path of the web application resource that will
101 * process this request via RequestDispatcher.include(), instead of
102 * instantiating and calling the <code>Action</code> class specified by
103 * "type". Exactly one of <code>forward</code>, <code>include</code>, or
104 * <code>type</code> must be specified. </p>
105 */
106 protected String include = null;
107
108 /***
109 * <p> Context-relative path of the input form to which control should be
110 * returned if a validation error is encountered. Required if "name" is
111 * specified and the input bean returns validation errors. </p>
112 */
113 protected String input = null;
114
115 /***
116 * <p> Fully qualified Java class name of the <code>MultipartRequestHandler</code>
117 * implementation class used to process multi-part request data for this
118 * Action. </p>
119 */
120 protected String multipartClass = null;
121
122 /***
123 * <p> Name of the form bean, if any, associated with this Action. </p>
124 */
125 protected String name = null;
126
127 /***
128 * <p> General purpose configuration parameter that can be used to pass
129 * extra information to the Action instance selected by this Action.
130 * Struts does not itself use this value in any way. </p>
131 */
132 protected String parameter = null;
133
134 /***
135 * <p> Context-relative path of the submitted request, starting with a
136 * slash ("/") character, and omitting any filename extension if extension
137 * mapping is being used. </p>
138 */
139 protected String path = null;
140
141 /***
142 * <p> Prefix used to match request parameter names to form bean property
143 * names, if any. </p>
144 */
145 protected String prefix = null;
146
147 /***
148 * <p> Comma-delimited list of security role names allowed to request this
149 * Action. </p>
150 */
151 protected String roles = null;
152
153 /***
154 * <p> The set of security role names used to authorize access to this
155 * Action, as an array for faster access. </p>
156 */
157 protected String[] roleNames = new String[0];
158
159 /***
160 * <p> Identifier of the scope ("request" or "session") within which our
161 * form bean is accessed, if any. </p>
162 */
163 protected String scope = "session";
164
165 /***
166 * <p> Suffix used to match request parameter names to form bean property
167 * names, if any. </p>
168 */
169 protected String suffix = null;
170
171 /***
172 * <p> Fully qualified Java class name of the <code>Action</code> class to
173 * be used to process requests for this mapping if the
174 * <code>forward</code> and <code>include</code> properties are not set.
175 * Exactly one of <code>forward</code>, <code>include</code>, or
176 * <code>type</code> must be specified.
177 */
178 protected String type = null;
179
180 /***
181 * <p> Indicates Action be configured as the default one for this module,
182 * when true.
183 */
184 protected boolean unknown = false;
185
186 /***
187 * <p> Should the <code>validate()</code> method of the form bean
188 * associated with this action be called?
189 */
190 protected boolean validate = true;
191
192 /***
193 * <p> The name of a <code>commons-chain</code> command which should be
194 * executed as part of the processing of this action.
195 *
196 * @since Struts 1.3.0
197 */
198 protected String command = null;
199
200 /***
201 * <p> The name of a <code>commons-chain</code> catalog in which
202 * <code>command</code> should be sought. If a <code>command</code> is
203 * defined and this property is undefined, the "default" catalog will be
204 * used. This is likely to be infrequently used after a future release of
205 * <code>commons-chain</code> supports a one-string expression of a
206 * catalog/chain combination.
207 *
208 * @since Struts 1.3.0
209 */
210 protected String catalog = null;
211
212 /***
213 * <p> The module configuration with which we are associated.
214 */
215 public ModuleConfig getModuleConfig() {
216 return (this.moduleConfig);
217 }
218
219 /***
220 * <p> The module configuration with which we are associated.
221 */
222 public void setModuleConfig(ModuleConfig moduleConfig) {
223 if (configured) {
224 throw new IllegalStateException("Configuration is frozen");
225 }
226
227 this.moduleConfig = moduleConfig;
228 }
229
230 /***
231 * <p> Returns the request-scope or session-scope attribute name under
232 * which our form bean is accessed, if it is different from the form
233 * bean's specified <code>name</code>.
234 *
235 * @return attribute name under which our form bean is accessed.
236 */
237 public String getAttribute() {
238 if (this.attribute == null) {
239 return (this.name);
240 } else {
241 return (this.attribute);
242 }
243 }
244
245 /***
246 * <p> Set the request-scope or session-scope attribute name under which
247 * our form bean is accessed, if it is different from the form bean's
248 * specified <code>name</code>.
249 *
250 * @param attribute the request-scope or session-scope attribute name
251 * under which our form bean is access.
252 */
253 public void setAttribute(String attribute) {
254 if (configured) {
255 throw new IllegalStateException("Configuration is frozen");
256 }
257
258 this.attribute = attribute;
259 }
260
261 /***
262 * <p>Accessor for cancellable property</p>
263 *
264 * @return True if Action can be cancelled
265 */
266 public boolean getCancellable() {
267 return (this.cancellable);
268 }
269
270 /***
271 * <p>Mutator for for cancellable property</p>
272 *
273 * @param cancellable
274 */
275 public void setCancellable(boolean cancellable) {
276 if (configured) {
277 throw new IllegalStateException("Configuration is frozen");
278 }
279
280 this.cancellable = cancellable;
281 }
282
283 /***
284 * <p>Returns the path of the ActionConfig that this object should inherit
285 * properties from.</p>
286 *
287 * @return the path of the ActionConfig that this object should inherit
288 * properties from.
289 */
290 public String getExtends() {
291 return (this.inherit);
292 }
293
294 /***
295 * <p>Set the path of the ActionConfig that this object should inherit
296 * properties from.</p>
297 *
298 * @param inherit the path of the ActionConfig that this object should
299 * inherit properties from.
300 */
301 public void setExtends(String inherit) {
302 if (configured) {
303 throw new IllegalStateException("Configuration is frozen");
304 }
305
306 this.inherit = inherit;
307 }
308
309 public boolean isExtensionProcessed() {
310 return extensionProcessed;
311 }
312
313 /***
314 * <p> Returns context-relative path of the web application resource that
315 * will process this request.
316 *
317 * @return context-relative path of the web application resource that will
318 * process this request.
319 */
320 public String getForward() {
321 return (this.forward);
322 }
323
324 /***
325 * <p> Set the context-relative path of the web application resource that
326 * will process this request. Exactly one of <code>forward</code>,
327 * <code>include</code>, or <code>type</code> must be specified.
328 *
329 * @param forward context-relative path of the web application resource
330 * that will process this request.
331 */
332 public void setForward(String forward) {
333 if (configured) {
334 throw new IllegalStateException("Configuration is frozen");
335 }
336
337 this.forward = forward;
338 }
339
340 /***
341 * <p> Context-relative path of the web application resource that will
342 * process this request.
343 *
344 * @return Context-relative path of the web application resource that will
345 * process this request.
346 */
347 public String getInclude() {
348 return (this.include);
349 }
350
351 /***
352 * <p> Set context-relative path of the web application resource that will
353 * process this request. Exactly one of <code>forward</code>,
354 * <code>include</code>, or <code>type</code> must be specified.
355 *
356 * @param include context-relative path of the web application resource
357 * that will process this request.
358 */
359 public void setInclude(String include) {
360 if (configured) {
361 throw new IllegalStateException("Configuration is frozen");
362 }
363
364 this.include = include;
365 }
366
367 /***
368 * <p> Get the context-relative path of the input form to which control
369 * should be returned if a validation error is encountered.
370 *
371 * @return context-relative path of the input form to which control should
372 * be returned if a validation error is encountered.
373 */
374 public String getInput() {
375 return (this.input);
376 }
377
378 /***
379 * <p> Set the context-relative path of the input form to which control
380 * should be returned if a validation error is encountered. Required if
381 * "name" is specified and the input bean returns validation errors.
382 *
383 * @param input context-relative path of the input form to which control
384 * should be returned if a validation error is encountered.
385 */
386 public void setInput(String input) {
387 if (configured) {
388 throw new IllegalStateException("Configuration is frozen");
389 }
390
391 this.input = input;
392 }
393
394 /***
395 * <p> Return the fully qualified Java class name of the
396 * <code>MultipartRequestHandler</code> implementation class used to
397 * process multi-part request data for this Action.
398 */
399 public String getMultipartClass() {
400 return (this.multipartClass);
401 }
402
403 /***
404 * <p> Set the fully qualified Java class name of the
405 * <code>MultipartRequestHandler</code> implementation class used to
406 * process multi-part request data for this Action.
407 *
408 * @param multipartClass fully qualified class name of the
409 * <code>MultipartRequestHandler</code>
410 * implementation class.
411 */
412 public void setMultipartClass(String multipartClass) {
413 if (configured) {
414 throw new IllegalStateException("Configuration is frozen");
415 }
416
417 this.multipartClass = multipartClass;
418 }
419
420 /***
421 * <p> Return name of the form bean, if any, associated with this Action.
422 */
423 public String getName() {
424 return (this.name);
425 }
426
427 /***
428 * @param name name of the form bean associated with this Action.
429 */
430 public void setName(String name) {
431 if (configured) {
432 throw new IllegalStateException("Configuration is frozen");
433 }
434
435 this.name = name;
436 }
437
438 /***
439 * <p> Return general purpose configuration parameter that can be used to
440 * pass extra information to the Action instance selected by this Action.
441 * Struts does not itself use this value in any way.
442 */
443 public String getParameter() {
444 return (this.parameter);
445 }
446
447 /***
448 * <p> General purpose configuration parameter that can be used to pass
449 * extra information to the Action instance selected by this Action.
450 * Struts does not itself use this value in any way.
451 *
452 * @param parameter General purpose configuration parameter.
453 */
454 public void setParameter(String parameter) {
455 if (configured) {
456 throw new IllegalStateException("Configuration is frozen");
457 }
458
459 this.parameter = parameter;
460 }
461
462 /***
463 * <p> Return context-relative path of the submitted request, starting
464 * with a slash ("/") character, and omitting any filename extension if
465 * extension mapping is being used.
466 */
467 public String getPath() {
468 return (this.path);
469 }
470
471 /***
472 * <p> Set context-relative path of the submitted request, starting with a
473 * slash ("/") character, and omitting any filename extension if extension
474 * mapping is being used.
475 *
476 * @param path context-relative path of the submitted request.
477 */
478 public void setPath(String path) {
479 if (configured) {
480 throw new IllegalStateException("Configuration is frozen");
481 }
482
483 this.path = path;
484 }
485
486 /***
487 * <p> Retruns prefix used to match request parameter names to form bean
488 * property names, if any.
489 */
490 public String getPrefix() {
491 return (this.prefix);
492 }
493
494 /***
495 * @param prefix Prefix used to match request parameter names to form bean
496 * property names, if any.
497 */
498 public void setPrefix(String prefix) {
499 if (configured) {
500 throw new IllegalStateException("Configuration is frozen");
501 }
502
503 this.prefix = prefix;
504 }
505
506 public String getRoles() {
507 return (this.roles);
508 }
509
510 public void setRoles(String roles) {
511 if (configured) {
512 throw new IllegalStateException("Configuration is frozen");
513 }
514
515 this.roles = roles;
516
517 if (roles == null) {
518 roleNames = new String[0];
519
520 return;
521 }
522
523 ArrayList list = new ArrayList();
524
525 while (true) {
526 int comma = roles.indexOf(',');
527
528 if (comma < 0) {
529 break;
530 }
531
532 list.add(roles.substring(0, comma).trim());
533 roles = roles.substring(comma + 1);
534 }
535
536 roles = roles.trim();
537
538 if (roles.length() > 0) {
539 list.add(roles);
540 }
541
542 roleNames = (String[]) list.toArray(new String[list.size()]);
543 }
544
545 /***
546 * <p> Get array of security role names used to authorize access to this
547 * Action.
548 */
549 public String[] getRoleNames() {
550 return (this.roleNames);
551 }
552
553 /***
554 * <p> Get the scope ("request" or "session") within which our form bean
555 * is accessed, if any.
556 */
557 public String getScope() {
558 return (this.scope);
559 }
560
561 /***
562 * @param scope scope ("request" or "session") within which our form bean
563 * is accessed, if any.
564 */
565 public void setScope(String scope) {
566 if (configured) {
567 throw new IllegalStateException("Configuration is frozen");
568 }
569
570 this.scope = scope;
571 }
572
573 /***
574 * <p> Return suffix used to match request parameter names to form bean
575 * property names, if any. </p>
576 */
577 public String getSuffix() {
578 return (this.suffix);
579 }
580
581 /***
582 * @param suffix Suffix used to match request parameter names to form bean
583 * property names, if any.
584 */
585 public void setSuffix(String suffix) {
586 if (configured) {
587 throw new IllegalStateException("Configuration is frozen");
588 }
589
590 this.suffix = suffix;
591 }
592
593 public String getType() {
594 return (this.type);
595 }
596
597 public void setType(String type) {
598 if (configured) {
599 throw new IllegalStateException("Configuration is frozen");
600 }
601
602 this.type = type;
603 }
604
605 /***
606 * <p> Determine whether Action is configured as the default one for this
607 * module. </p>
608 */
609 public boolean getUnknown() {
610 return (this.unknown);
611 }
612
613 /***
614 * @param unknown Indicates Action is configured as the default one for
615 * this module, when true.
616 */
617 public void setUnknown(boolean unknown) {
618 if (configured) {
619 throw new IllegalStateException("Configuration is frozen");
620 }
621
622 this.unknown = unknown;
623 }
624
625 public boolean getValidate() {
626 return (this.validate);
627 }
628
629 public void setValidate(boolean validate) {
630 if (configured) {
631 throw new IllegalStateException("Configuration is frozen");
632 }
633
634 this.validate = validate;
635 }
636
637 /***
638 * <p> Get the name of a <code>commons-chain</code> command which should
639 * be executed as part of the processing of this action. </p>
640 *
641 * @return name of a <code>commons-chain</code> command which should be
642 * executed as part of the processing of this action.
643 * @since Struts 1.3.0
644 */
645 public String getCommand() {
646 return (this.command);
647 }
648
649 /***
650 * <p> Get the name of a <code>commons-chain</code> catalog in which a
651 * specified command should be sought. This is likely to be infrequently
652 * used after a future release of <code>commons-chain</code> supports a
653 * one-string expression of a catalog/chain combination. </p>
654 *
655 * @return name of a <code>commons-chain</code> catalog in which a
656 * specified command should be sought.
657 * @since Struts 1.3.0
658 */
659 public String getCatalog() {
660 return (this.catalog);
661 }
662
663 /***
664 * <p> Set the name of a <code>commons-chain</code> command which should
665 * be executed as part of the processing of this action. </p>
666 *
667 * @param command name of a <code>commons-chain</code> command which
668 * should be executed as part of the processing of this
669 * action.
670 * @since Struts 1.3.0
671 */
672 public void setCommand(String command) {
673 if (configured) {
674 throw new IllegalStateException("Configuration is frozen");
675 }
676
677 this.command = command;
678 }
679
680 /***
681 * <p> Set the name of a <code>commons-chain</code> catalog in which a
682 * specified command should be sought. This is likely to be infrequently
683 * used after a future release of <code>commons-chain</code> supports a
684 * one-string expression of a catalog/chain combination. </p>
685 *
686 * @param catalog name of a <code>commons-chain</code> catalog in which a
687 * specified command should be sought.
688 * @since Struts 1.3.0
689 */
690 public void setCatalog(String catalog) {
691 if (configured) {
692 throw new IllegalStateException("Configuration is frozen");
693 }
694
695 this.catalog = catalog;
696 }
697
698
699
700 /***
701 * <p>Traces the hierarchy of this object to check if any of the ancestors
702 * is extending this instance.</p>
703 *
704 * @param moduleConfig The configuration for the module being configured.
705 * @return true if circular inheritance was detected.
706 */
707 protected boolean checkCircularInheritance(ModuleConfig moduleConfig) {
708 String ancestorPath = getExtends();
709
710 while (ancestorPath != null) {
711
712 if (getPath().equals(ancestorPath)) {
713 return true;
714 }
715
716
717 ActionConfig ancestor = moduleConfig.findActionConfig(ancestorPath);
718
719 if (ancestor != null) {
720 ancestorPath = ancestor.getExtends();
721 } else {
722 ancestorPath = null;
723 }
724 }
725
726 return false;
727 }
728
729 /***
730 * <p>Compare the exception handlers of this action with that of the given
731 * and copy those that are not present.</p>
732 *
733 * @param baseConfig The action config to copy handlers from.
734 * @see #inheritFrom(ActionConfig)
735 */
736 protected void inheritExceptionHandlers(ActionConfig baseConfig)
737 throws ClassNotFoundException, IllegalAccessException,
738 InstantiationException, InvocationTargetException {
739 if (configured) {
740 throw new IllegalStateException("Configuration is frozen");
741 }
742
743
744 ExceptionConfig[] baseHandlers = baseConfig.findExceptionConfigs();
745
746 for (int i = 0; i < baseHandlers.length; i++) {
747 ExceptionConfig baseHandler = baseHandlers[i];
748
749
750 ExceptionConfig copy =
751 this.findExceptionConfig(baseHandler.getType());
752
753 if (copy == null) {
754
755 copy =
756 (ExceptionConfig) RequestUtils.applicationInstance(baseHandler.getClass()
757 .getName());
758
759 BeanUtils.copyProperties(copy, baseHandler);
760 this.addExceptionConfig(copy);
761 copy.setProperties(baseHandler.copyProperties());
762 } else {
763
764 copy.processExtends(getModuleConfig(), this);
765 }
766 }
767 }
768
769 /***
770 * <p>Compare the forwards of this action with that of the given and copy
771 * those that are not present.</p>
772 *
773 * @param baseConfig The action config to copy forwards from.
774 * @see #inheritFrom(ActionConfig)
775 */
776 protected void inheritForwards(ActionConfig baseConfig)
777 throws ClassNotFoundException, IllegalAccessException,
778 InstantiationException, InvocationTargetException {
779 if (configured) {
780 throw new IllegalStateException("Configuration is frozen");
781 }
782
783
784 ForwardConfig[] baseForwards = baseConfig.findForwardConfigs();
785
786 for (int i = 0; i < baseForwards.length; i++) {
787 ForwardConfig baseForward = baseForwards[i];
788
789
790 ForwardConfig copy = this.findForwardConfig(baseForward.getName());
791
792 if (copy == null) {
793
794 copy =
795 (ForwardConfig) RequestUtils.applicationInstance(baseForward.getClass()
796 .getName());
797 BeanUtils.copyProperties(copy, baseForward);
798
799 this.addForwardConfig(copy);
800 copy.setProperties(baseForward.copyProperties());
801 } else {
802
803 copy.processExtends(getModuleConfig(), this);
804 }
805 }
806 }
807
808
809
810 /***
811 * <p> Add a new <code>ExceptionConfig</code> instance to the set
812 * associated with this action. </p>
813 *
814 * @param config The new configuration instance to be added
815 * @throws IllegalStateException if this module configuration has been
816 * frozen
817 */
818 public void addExceptionConfig(ExceptionConfig config) {
819 if (configured) {
820 throw new IllegalStateException("Configuration is frozen");
821 }
822
823 exceptions.put(config.getType(), config);
824 }
825
826 /***
827 * <p> Add a new <code>ForwardConfig</code> instance to the set of global
828 * forwards associated with this action. </p>
829 *
830 * @param config The new configuration instance to be added
831 * @throws IllegalStateException if this module configuration has been
832 * frozen
833 */
834 public void addForwardConfig(ForwardConfig config) {
835 if (configured) {
836 throw new IllegalStateException("Configuration is frozen");
837 }
838
839 forwards.put(config.getName(), config);
840 }
841
842 /***
843 * <p> Return the exception configuration for the specified type, if any;
844 * otherwise return <code>null</code>. </p>
845 *
846 * @param type Exception class name to find a configuration for
847 */
848 public ExceptionConfig findExceptionConfig(String type) {
849 return ((ExceptionConfig) exceptions.get(type));
850 }
851
852 /***
853 * <p> Return the exception configurations for this action. If there are
854 * none, a zero-length array is returned. </p>
855 */
856 public ExceptionConfig[] findExceptionConfigs() {
857 ExceptionConfig[] results = new ExceptionConfig[exceptions.size()];
858
859 return ((ExceptionConfig[]) exceptions.values().toArray(results));
860 }
861
862 /***
863 * <p>Find and return the <code>ExceptionConfig</code> instance defining
864 * how <code>Exceptions</code> of the specified type should be handled.
865 * This is performed by checking local and then global configurations for
866 * the specified exception's class, and then looking up the superclass
867 * chain (again checking local and then global configurations). If no
868 * handler configuration can be found, return <code>null</code>.</p>
869 *
870 * <p>Introduced in <code>ActionMapping</code> in Struts 1.1, but pushed
871 * up to <code>ActionConfig</code> in Struts 1.2.0.</p>
872 *
873 * @param type Exception class for which to find a handler
874 * @since Struts 1.2.0
875 */
876 public ExceptionConfig findException(Class type) {
877
878 ExceptionConfig config;
879
880 while (true) {
881
882 String name = type.getName();
883
884 log.debug("findException: look locally for " + name);
885 config = findExceptionConfig(name);
886
887 if (config != null) {
888 return (config);
889 }
890
891
892 log.debug("findException: look globally for " + name);
893 config = getModuleConfig().findExceptionConfig(name);
894
895 if (config != null) {
896 return (config);
897 }
898
899
900 type = type.getSuperclass();
901
902 if (type == null) {
903 break;
904 }
905 }
906
907 return (null);
908 }
909
910 /***
911 * <p> Return the forward configuration for the specified key, if any;
912 * otherwise return <code>null</code>. </p>
913 *
914 * @param name Name of the forward configuration to return
915 */
916 public ForwardConfig findForwardConfig(String name) {
917 return ((ForwardConfig) forwards.get(name));
918 }
919
920 /***
921 * <p> Return all forward configurations for this module. If there are
922 * none, a zero-length array is returned. </p>
923 */
924 public ForwardConfig[] findForwardConfigs() {
925 ForwardConfig[] results = new ForwardConfig[forwards.size()];
926
927 return ((ForwardConfig[]) forwards.values().toArray(results));
928 }
929
930 /***
931 * <p> Freeze the configuration of this action. </p>
932 */
933 public void freeze() {
934 super.freeze();
935
936 ExceptionConfig[] econfigs = findExceptionConfigs();
937
938 for (int i = 0; i < econfigs.length; i++) {
939 econfigs[i].freeze();
940 }
941
942 ForwardConfig[] fconfigs = findForwardConfigs();
943
944 for (int i = 0; i < fconfigs.length; i++) {
945 fconfigs[i].freeze();
946 }
947 }
948
949 /***
950 * <p>Inherit values that have not been overridden from the provided
951 * config object. Subclasses overriding this method should verify that
952 * the given parameter is of a class that contains a property it is trying
953 * to inherit:</p>
954 *
955 * <pre>
956 * if (config instanceof MyCustomConfig) {
957 * MyCustomConfig myConfig =
958 * (MyCustomConfig) config;
959 *
960 * if (getMyCustomProp() == null) {
961 * setMyCustomProp(myConfig.getMyCustomProp());
962 * }
963 * }
964 * </pre>
965 *
966 * <p>If the given <code>config</code> is extending another object, those
967 * extensions should be resolved before it's used as a parameter to this
968 * method.</p>
969 *
970 * @param config The object that this instance will be inheriting its
971 * values from.
972 * @see #processExtends(ModuleConfig)
973 */
974 public void inheritFrom(ActionConfig config)
975 throws ClassNotFoundException, IllegalAccessException,
976 InstantiationException, InvocationTargetException {
977 if (configured) {
978 throw new IllegalStateException("Configuration is frozen");
979 }
980
981
982 if (getAttribute() == null) {
983 setAttribute(config.getAttribute());
984 }
985
986 if (!getCancellable()) {
987 setCancellable(config.getCancellable());
988 }
989
990 if (getCatalog() == null) {
991 setCatalog(config.getCatalog());
992 }
993
994 if (getCommand() == null) {
995 setCommand(config.getCommand());
996 }
997
998 if (getForward() == null) {
999 setForward(config.getForward());
1000 }
1001
1002 if (getInclude() == null) {
1003 setInclude(config.getInclude());
1004 }
1005
1006 if (getInput() == null) {
1007 setInput(config.getInput());
1008 }
1009
1010 if (getMultipartClass() == null) {
1011 setMultipartClass(config.getMultipartClass());
1012 }
1013
1014 if (getName() == null) {
1015 setName(config.getName());
1016 }
1017
1018 if (getParameter() == null) {
1019 setParameter(config.getParameter());
1020 }
1021
1022 if (getPath() == null) {
1023 setPath(config.getPath());
1024 }
1025
1026 if (getPrefix() == null) {
1027 setPrefix(config.getPrefix());
1028 }
1029
1030 if (getRoles() == null) {
1031 setRoles(config.getRoles());
1032 }
1033
1034 if (getScope().equals("session")) {
1035 setScope(config.getScope());
1036 }
1037
1038 if (getSuffix() == null) {
1039 setSuffix(config.getSuffix());
1040 }
1041
1042 if (getType() == null) {
1043 setType(config.getType());
1044 }
1045
1046 if (!getUnknown()) {
1047 setUnknown(config.getUnknown());
1048 }
1049
1050 if (getValidate()) {
1051 setValidate(config.getValidate());
1052 }
1053
1054 inheritExceptionHandlers(config);
1055 inheritForwards(config);
1056 inheritProperties(config);
1057 }
1058
1059 /***
1060 * <p>Inherit configuration information from the ActionConfig that this
1061 * instance is extending. This method verifies that any action config
1062 * object that it inherits from has also had its processExtends() method
1063 * called.</p>
1064 *
1065 * @param moduleConfig The {@link ModuleConfig} that this bean is from.
1066 * @see #inheritFrom(ActionConfig)
1067 */
1068 public void processExtends(ModuleConfig moduleConfig)
1069 throws ClassNotFoundException, IllegalAccessException,
1070 InstantiationException, InvocationTargetException {
1071 if (configured) {
1072 throw new IllegalStateException("Configuration is frozen");
1073 }
1074
1075 String ancestorPath = getExtends();
1076
1077 if ((!extensionProcessed) && (ancestorPath != null)) {
1078 ActionConfig baseConfig =
1079 moduleConfig.findActionConfig(ancestorPath);
1080
1081 if (baseConfig == null) {
1082 throw new NullPointerException("Unable to find "
1083 + "action for '" + ancestorPath + "' to extend.");
1084 }
1085
1086
1087
1088 if (checkCircularInheritance(moduleConfig)) {
1089 throw new IllegalArgumentException(
1090 "Circular inheritance detected for action " + getPath());
1091 }
1092
1093
1094 if (!baseConfig.isExtensionProcessed()) {
1095 baseConfig.processExtends(moduleConfig);
1096 }
1097
1098
1099 inheritFrom(baseConfig);
1100 }
1101
1102 extensionProcessed = true;
1103 }
1104
1105 /***
1106 * <p> Remove the specified exception configuration instance. </p>
1107 *
1108 * @param config ExceptionConfig instance to be removed
1109 * @throws IllegalStateException if this module configuration has been
1110 * frozen
1111 */
1112 public void removeExceptionConfig(ExceptionConfig config) {
1113 if (configured) {
1114 throw new IllegalStateException("Configuration is frozen");
1115 }
1116
1117 exceptions.remove(config.getType());
1118 }
1119
1120 /***
1121 * <p> Remove the specified forward configuration instance. </p>
1122 *
1123 * @param config ForwardConfig instance to be removed
1124 * @throws IllegalStateException if this module configuration has been
1125 * frozen
1126 */
1127 public void removeForwardConfig(ForwardConfig config) {
1128 if (configured) {
1129 throw new IllegalStateException("Configuration is frozen");
1130 }
1131
1132 forwards.remove(config.getName());
1133 }
1134
1135 /***
1136 * <p> Return a String representation of this object. </p>
1137 */
1138 public String toString() {
1139 StringBuffer sb = new StringBuffer("ActionConfig[");
1140
1141 sb.append("cancellable=");
1142 sb.append(cancellable);
1143
1144 sb.append("path=");
1145 sb.append(path);
1146
1147 sb.append("validate=");
1148 sb.append(validate);
1149
1150 if (attribute != null) {
1151 sb.append(",attribute=");
1152 sb.append(attribute);
1153 }
1154
1155 if (catalog != null) {
1156 sb.append(",catalog=");
1157 sb.append(catalog);
1158 }
1159
1160 if (command != null) {
1161 sb.append(",command=");
1162 sb.append(command);
1163 }
1164
1165 if (inherit != null) {
1166 sb.append(",extends=");
1167 sb.append(inherit);
1168 }
1169
1170 if (forward != null) {
1171 sb.append(",forward=");
1172 sb.append(forward);
1173 }
1174
1175 if (include != null) {
1176 sb.append(",include=");
1177 sb.append(include);
1178 }
1179
1180 if (input != null) {
1181 sb.append(",input=");
1182 sb.append(input);
1183 }
1184
1185 if (multipartClass != null) {
1186 sb.append(",multipartClass=");
1187 sb.append(multipartClass);
1188 }
1189
1190 if (name != null) {
1191 sb.append(",name=");
1192 sb.append(name);
1193 }
1194
1195 if (parameter != null) {
1196 sb.append(",parameter=");
1197 sb.append(parameter);
1198 }
1199
1200 if (prefix != null) {
1201 sb.append(",prefix=");
1202 sb.append(prefix);
1203 }
1204
1205 if (roles != null) {
1206 sb.append(",roles=");
1207 sb.append(roles);
1208 }
1209
1210 if (scope != null) {
1211 sb.append(",scope=");
1212 sb.append(scope);
1213 }
1214
1215 if (suffix != null) {
1216 sb.append(",suffix=");
1217 sb.append(suffix);
1218 }
1219
1220 if (type != null) {
1221 sb.append(",type=");
1222 sb.append(type);
1223 }
1224
1225 return (sb.toString());
1226 }
1227 }