View Javadoc

1   /*
2    * $Id: ExceptionConfig.java 421119 2006-07-12 04:49:11Z wsmoak $
3    *
4    * Copyright 1999-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts.config;
19  
20  import java.lang.reflect.InvocationTargetException;
21  
22  /***
23   * <p>A JavaBean representing the configuration information of an
24   * <code>&lt;exception&gt;</code> element from a Struts configuration
25   * file.</p>
26   *
27   * @version $Rev: 421119 $ $Date: 2005-08-06 18:03:30 -0400 (Sat, 06 Aug 2005)
28   *          $
29   * @since Struts 1.1
30   */
31  public class ExceptionConfig extends BaseConfig {
32      // ------------------------------------------------------------- Properties
33  
34      /***
35       * The servlet context attribute under which the message resources bundle
36       * to be used for this exception is located.  If not set, the default
37       * message resources for the current module is assumed.
38       */
39      protected String bundle = null;
40  
41      /***
42       * The type of the ExceptionConfig that this object should inherit
43       * properties from.
44       */
45      protected String inherit = null;
46  
47      /***
48       * Have the inheritance values for this class been applied?
49       */
50      protected boolean extensionProcessed = false;
51  
52      /***
53       * The fully qualified Java class name of the exception handler class
54       * which should be instantiated to handle this exception.
55       */
56      protected String handler = "org.apache.struts.action.ExceptionHandler";
57  
58      /***
59       * The message resources key specifying the error message associated with
60       * this exception.
61       */
62      protected String key = null;
63  
64      /***
65       * The module-relative path of the resource to forward to if this
66       * exception occurs during an <code>Action</code>.
67       */
68      protected String path = null;
69  
70      /***
71       * The scope in which we should expose the ActionMessage for this
72       * exception handler.
73       */
74      protected String scope = "request";
75  
76      /***
77       * The fully qualified Java class name of the exception that is to be
78       * handled by this handler.
79       */
80      protected String type = null;
81  
82      public String getBundle() {
83          return (this.bundle);
84      }
85  
86      public void setBundle(String bundle) {
87          if (configured) {
88              throw new IllegalStateException("Configuration is frozen");
89          }
90  
91          this.bundle = bundle;
92      }
93  
94      public String getExtends() {
95          return (this.inherit);
96      }
97  
98      public void setExtends(String inherit) {
99          if (configured) {
100             throw new IllegalStateException("Configuration is frozen");
101         }
102 
103         this.inherit = inherit;
104     }
105 
106     public boolean isExtensionProcessed() {
107         return extensionProcessed;
108     }
109 
110     public String getHandler() {
111         return (this.handler);
112     }
113 
114     public void setHandler(String handler) {
115         if (configured) {
116             throw new IllegalStateException("Configuration is frozen");
117         }
118 
119         this.handler = handler;
120     }
121 
122     public String getKey() {
123         return (this.key);
124     }
125 
126     public void setKey(String key) {
127         if (configured) {
128             throw new IllegalStateException("Configuration is frozen");
129         }
130 
131         this.key = key;
132     }
133 
134     public String getPath() {
135         return (this.path);
136     }
137 
138     public void setPath(String path) {
139         if (configured) {
140             throw new IllegalStateException("Configuration is frozen");
141         }
142 
143         this.path = path;
144     }
145 
146     public String getScope() {
147         return (this.scope);
148     }
149 
150     public void setScope(String scope) {
151         if (configured) {
152             throw new IllegalStateException("Configuration is frozen");
153         }
154 
155         this.scope = scope;
156     }
157 
158     public String getType() {
159         return (this.type);
160     }
161 
162     public void setType(String type) {
163         if (configured) {
164             throw new IllegalStateException("Configuration is frozen");
165         }
166 
167         this.type = type;
168     }
169 
170     // ------------------------------------------------------ Protected Methods
171 
172     /***
173      * <p>Traces the hierarchy of this object to check if any of the ancestors
174      * are extending this instance.</p>
175      *
176      * @param moduleConfig The {@link ModuleConfig} that this config is from.
177      * @param actionConfig The {@link ActionConfig} that this config is from,
178      *                     if applicable.  This parameter must be null if this
179      *                     is a global handler.
180      * @return true if circular inheritance was detected.
181      */
182     protected boolean checkCircularInheritance(ModuleConfig moduleConfig,
183         ActionConfig actionConfig) {
184         String ancestorType = getExtends();
185 
186         if (ancestorType == null) {
187             return false;
188         }
189 
190         // Find our ancestor
191         ExceptionConfig ancestor = null;
192 
193         // First check the action config
194         if (actionConfig != null) {
195             ancestor = actionConfig.findExceptionConfig(ancestorType);
196 
197             // If we found *this*, set ancestor to null to check for a global def
198             if (ancestor == this) {
199                 ancestor = null;
200             }
201         }
202 
203         // Then check the global handlers
204         if (ancestor == null) {
205             ancestor = moduleConfig.findExceptionConfig(ancestorType);
206 
207             if (ancestor != null) {
208                 // If the ancestor is a global handler, set actionConfig
209                 //  to null so further searches are only done among
210                 //  global handlers.
211                 actionConfig = null;
212             }
213         }
214 
215         while (ancestor != null) {
216             // Check if an ancestor is extending *this*
217             if (ancestor == this) {
218                 return true;
219             }
220 
221             // Get our ancestor's ancestor
222             ancestorType = ancestor.getExtends();
223 
224             // check against ancestors extending same typed ancestors
225             if (ancestor.getType().equals(ancestorType)) {
226                 // If the ancestor is extending a config for the same type,
227                 //  make sure we look for its ancestor in the global handlers.
228                 //  If we're already at that level, we return false.
229                 if (actionConfig == null) {
230                     return false;
231                 } else {
232                     // Set actionConfig = null to force us to look for global
233                     //  forwards
234                     actionConfig = null;
235                 }
236             }
237 
238             ancestor = null;
239 
240             // First check the action config
241             if (actionConfig != null) {
242                 ancestor = actionConfig.findExceptionConfig(ancestorType);
243             }
244 
245             // Then check the global handlers
246             if (ancestor == null) {
247                 ancestor = moduleConfig.findExceptionConfig(ancestorType);
248 
249                 if (ancestor != null) {
250                     // Limit further checks to moduleConfig.
251                     actionConfig = null;
252                 }
253             }
254         }
255 
256         return false;
257     }
258 
259     // --------------------------------------------------------- Public Methods
260 
261     /***
262      * <p>Inherit values that have not been overridden from the provided
263      * config object.  Subclasses overriding this method should verify that
264      * the given parameter is of a class that contains a property it is trying
265      * to inherit:</p>
266      *
267      * <pre>
268      * if (config instanceof MyCustomConfig) {
269      *     MyCustomConfig myConfig =
270      *         (MyCustomConfig) config;
271      *
272      *     if (getMyCustomProp() == null) {
273      *         setMyCustomProp(myConfig.getMyCustomProp());
274      *     }
275      * }
276      * </pre>
277      *
278      * <p>If the given <code>config</code> is extending another object, those
279      * extensions should be resolved before it's used as a parameter to this
280      * method.</p>
281      *
282      * @param config The object that this instance will be inheriting its
283      *               values from.
284      * @see #processExtends(ModuleConfig, ActionConfig)
285      */
286     public void inheritFrom(ExceptionConfig config)
287         throws ClassNotFoundException, IllegalAccessException,
288             InstantiationException, InvocationTargetException {
289         if (configured) {
290             throw new IllegalStateException("Configuration is frozen");
291         }
292 
293         // Inherit values that have not been overridden
294         if (getBundle() == null) {
295             setBundle(config.getBundle());
296         }
297 
298         if (getHandler().equals("org.apache.struts.action.ExceptionHandler")) {
299             setHandler(config.getHandler());
300         }
301 
302         if (getKey() == null) {
303             setKey(config.getKey());
304         }
305 
306         if (getPath() == null) {
307             setPath(config.getPath());
308         }
309 
310         if (getScope().equals("request")) {
311             setScope(config.getScope());
312         }
313 
314         if (getType() == null) {
315             setType(config.getType());
316         }
317 
318         inheritProperties(config);
319     }
320 
321     /***
322      * <p>Inherit configuration information from the ExceptionConfig that this
323      * instance is extending.  This method verifies that any exception config
324      * object that it inherits from has also had its processExtends() method
325      * called.</p>
326      *
327      * @param moduleConfig The {@link ModuleConfig} that this config is from.
328      * @param actionConfig The {@link ActionConfig} that this config is from,
329      *                     if applicable.  This must be null for global
330      *                     forwards.
331      * @see #inheritFrom(ExceptionConfig)
332      */
333     public void processExtends(ModuleConfig moduleConfig,
334         ActionConfig actionConfig)
335         throws ClassNotFoundException, IllegalAccessException,
336             InstantiationException, InvocationTargetException {
337         if (configured) {
338             throw new IllegalStateException("Configuration is frozen");
339         }
340 
341         String ancestorType = getExtends();
342 
343         if ((!extensionProcessed) && (ancestorType != null)) {
344             ExceptionConfig baseConfig = null;
345 
346             // We only check the action config if we're not a global handler
347             boolean checkActionConfig =
348                 (this != moduleConfig.findExceptionConfig(getType()));
349 
350             // ... and the action config was provided
351             checkActionConfig &= (actionConfig != null);
352 
353             // ... and we're not extending a config with the same type value
354             // (because if we are, that means we're an action-level handler
355             //  extending a global handler).
356             checkActionConfig &= !ancestorType.equals(getType());
357 
358             // We first check in the action config's exception handlers
359             if (checkActionConfig) {
360                 baseConfig = actionConfig.findExceptionConfig(ancestorType);
361             }
362 
363             // Then check the global exception handlers
364             if (baseConfig == null) {
365                 baseConfig = moduleConfig.findExceptionConfig(ancestorType);
366             }
367 
368             if (baseConfig == null) {
369                 throw new NullPointerException("Unable to find "
370                     + "handler for '" + ancestorType + "' to extend.");
371             }
372 
373             // Check for circular inheritance and make sure the base config's
374             //  own inheritance has been processed already
375             if (checkCircularInheritance(moduleConfig, actionConfig)) {
376                 throw new IllegalArgumentException(
377                     "Circular inheritance detected for forward " + getType());
378             }
379 
380             if (!baseConfig.isExtensionProcessed()) {
381                 baseConfig.processExtends(moduleConfig, actionConfig);
382             }
383 
384             // copy values from the base config
385             inheritFrom(baseConfig);
386         }
387 
388         extensionProcessed = true;
389     }
390 
391     /***
392      * Return a String representation of this object.
393      */
394     public String toString() {
395         StringBuffer sb = new StringBuffer("ExceptionConfig[");
396 
397         sb.append("type=");
398         sb.append(this.type);
399 
400         if (this.bundle != null) {
401             sb.append(",bundle=");
402             sb.append(this.bundle);
403         }
404 
405         if (this.inherit != null) {
406             sb.append(",extends=");
407             sb.append(this.inherit);
408         }
409 
410         sb.append(",handler=");
411         sb.append(this.handler);
412         sb.append(",key=");
413         sb.append(this.key);
414         sb.append(",path=");
415         sb.append(this.path);
416         sb.append(",scope=");
417         sb.append(this.scope);
418         sb.append("]");
419 
420         return (sb.toString());
421     }
422 }