001: /*
002: * $Id: ExceptionConfig.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts.config;
022:
023: import java.lang.reflect.InvocationTargetException;
024:
025: /**
026: * <p>A JavaBean representing the configuration information of an
027: * <code><exception></code> element from a Struts configuration
028: * file.</p>
029: *
030: * @version $Rev: 471754 $ $Date: 2005-08-06 18:03:30 -0400 (Sat, 06 Aug 2005)
031: * $
032: * @since Struts 1.1
033: */
034: public class ExceptionConfig extends BaseConfig {
035: // ------------------------------------------------------------- Properties
036:
037: /**
038: * The servlet context attribute under which the message resources bundle
039: * to be used for this exception is located. If not set, the default
040: * message resources for the current module is assumed.
041: */
042: protected String bundle = null;
043:
044: /**
045: * The type of the ExceptionConfig that this object should inherit
046: * properties from.
047: */
048: protected String inherit = null;
049:
050: /**
051: * Have the inheritance values for this class been applied?
052: */
053: protected boolean extensionProcessed = false;
054:
055: /**
056: * The fully qualified Java class name of the exception handler class
057: * which should be instantiated to handle this exception.
058: */
059: protected String handler = "org.apache.struts.action.ExceptionHandler";
060:
061: /**
062: * The message resources key specifying the error message associated with
063: * this exception.
064: */
065: protected String key = null;
066:
067: /**
068: * The module-relative path of the resource to forward to if this
069: * exception occurs during an <code>Action</code>.
070: */
071: protected String path = null;
072:
073: /**
074: * The scope in which we should expose the ActionMessage for this
075: * exception handler.
076: */
077: protected String scope = "request";
078:
079: /**
080: * The fully qualified Java class name of the exception that is to be
081: * handled by this handler.
082: */
083: protected String type = null;
084:
085: public String getBundle() {
086: return (this .bundle);
087: }
088:
089: public void setBundle(String bundle) {
090: if (configured) {
091: throw new IllegalStateException("Configuration is frozen");
092: }
093:
094: this .bundle = bundle;
095: }
096:
097: public String getExtends() {
098: return (this .inherit);
099: }
100:
101: public void setExtends(String inherit) {
102: if (configured) {
103: throw new IllegalStateException("Configuration is frozen");
104: }
105:
106: this .inherit = inherit;
107: }
108:
109: public boolean isExtensionProcessed() {
110: return extensionProcessed;
111: }
112:
113: public String getHandler() {
114: return (this .handler);
115: }
116:
117: public void setHandler(String handler) {
118: if (configured) {
119: throw new IllegalStateException("Configuration is frozen");
120: }
121:
122: this .handler = handler;
123: }
124:
125: public String getKey() {
126: return (this .key);
127: }
128:
129: public void setKey(String key) {
130: if (configured) {
131: throw new IllegalStateException("Configuration is frozen");
132: }
133:
134: this .key = key;
135: }
136:
137: public String getPath() {
138: return (this .path);
139: }
140:
141: public void setPath(String path) {
142: if (configured) {
143: throw new IllegalStateException("Configuration is frozen");
144: }
145:
146: this .path = path;
147: }
148:
149: public String getScope() {
150: return (this .scope);
151: }
152:
153: public void setScope(String scope) {
154: if (configured) {
155: throw new IllegalStateException("Configuration is frozen");
156: }
157:
158: this .scope = scope;
159: }
160:
161: public String getType() {
162: return (this .type);
163: }
164:
165: public void setType(String type) {
166: if (configured) {
167: throw new IllegalStateException("Configuration is frozen");
168: }
169:
170: this .type = type;
171: }
172:
173: // ------------------------------------------------------ Protected Methods
174:
175: /**
176: * <p>Traces the hierarchy of this object to check if any of the ancestors
177: * are extending this instance.</p>
178: *
179: * @param moduleConfig The {@link ModuleConfig} that this config is from.
180: * @param actionConfig The {@link ActionConfig} that this config is from,
181: * if applicable. This parameter must be null if this
182: * is a global handler.
183: * @return true if circular inheritance was detected.
184: */
185: protected boolean checkCircularInheritance(
186: ModuleConfig moduleConfig, ActionConfig actionConfig) {
187: String ancestorType = getExtends();
188:
189: if (ancestorType == null) {
190: return false;
191: }
192:
193: // Find our ancestor
194: ExceptionConfig ancestor = null;
195:
196: // First check the action config
197: if (actionConfig != null) {
198: ancestor = actionConfig.findExceptionConfig(ancestorType);
199:
200: // If we found *this*, set ancestor to null to check for a global def
201: if (ancestor == this ) {
202: ancestor = null;
203: }
204: }
205:
206: // Then check the global handlers
207: if (ancestor == null) {
208: ancestor = moduleConfig.findExceptionConfig(ancestorType);
209:
210: if (ancestor != null) {
211: // If the ancestor is a global handler, set actionConfig
212: // to null so further searches are only done among
213: // global handlers.
214: actionConfig = null;
215: }
216: }
217:
218: while (ancestor != null) {
219: // Check if an ancestor is extending *this*
220: if (ancestor == this ) {
221: return true;
222: }
223:
224: // Get our ancestor's ancestor
225: ancestorType = ancestor.getExtends();
226:
227: // check against ancestors extending same typed ancestors
228: if (ancestor.getType().equals(ancestorType)) {
229: // If the ancestor is extending a config for the same type,
230: // make sure we look for its ancestor in the global handlers.
231: // If we're already at that level, we return false.
232: if (actionConfig == null) {
233: return false;
234: } else {
235: // Set actionConfig = null to force us to look for global
236: // forwards
237: actionConfig = null;
238: }
239: }
240:
241: ancestor = null;
242:
243: // First check the action config
244: if (actionConfig != null) {
245: ancestor = actionConfig
246: .findExceptionConfig(ancestorType);
247: }
248:
249: // Then check the global handlers
250: if (ancestor == null) {
251: ancestor = moduleConfig
252: .findExceptionConfig(ancestorType);
253:
254: if (ancestor != null) {
255: // Limit further checks to moduleConfig.
256: actionConfig = null;
257: }
258: }
259: }
260:
261: return false;
262: }
263:
264: // --------------------------------------------------------- Public Methods
265:
266: /**
267: * <p>Inherit values that have not been overridden from the provided
268: * config object. Subclasses overriding this method should verify that
269: * the given parameter is of a class that contains a property it is trying
270: * to inherit:</p>
271: *
272: * <pre>
273: * if (config instanceof MyCustomConfig) {
274: * MyCustomConfig myConfig =
275: * (MyCustomConfig) config;
276: *
277: * if (getMyCustomProp() == null) {
278: * setMyCustomProp(myConfig.getMyCustomProp());
279: * }
280: * }
281: * </pre>
282: *
283: * <p>If the given <code>config</code> is extending another object, those
284: * extensions should be resolved before it's used as a parameter to this
285: * method.</p>
286: *
287: * @param config The object that this instance will be inheriting its
288: * values from.
289: * @see #processExtends(ModuleConfig, ActionConfig)
290: */
291: public void inheritFrom(ExceptionConfig config)
292: throws ClassNotFoundException, IllegalAccessException,
293: InstantiationException, InvocationTargetException {
294: if (configured) {
295: throw new IllegalStateException("Configuration is frozen");
296: }
297:
298: // Inherit values that have not been overridden
299: if (getBundle() == null) {
300: setBundle(config.getBundle());
301: }
302:
303: if (getHandler().equals(
304: "org.apache.struts.action.ExceptionHandler")) {
305: setHandler(config.getHandler());
306: }
307:
308: if (getKey() == null) {
309: setKey(config.getKey());
310: }
311:
312: if (getPath() == null) {
313: setPath(config.getPath());
314: }
315:
316: if (getScope().equals("request")) {
317: setScope(config.getScope());
318: }
319:
320: if (getType() == null) {
321: setType(config.getType());
322: }
323:
324: inheritProperties(config);
325: }
326:
327: /**
328: * <p>Inherit configuration information from the ExceptionConfig that this
329: * instance is extending. This method verifies that any exception config
330: * object that it inherits from has also had its processExtends() method
331: * called.</p>
332: *
333: * @param moduleConfig The {@link ModuleConfig} that this config is from.
334: * @param actionConfig The {@link ActionConfig} that this config is from,
335: * if applicable. This must be null for global
336: * forwards.
337: * @see #inheritFrom(ExceptionConfig)
338: */
339: public void processExtends(ModuleConfig moduleConfig,
340: ActionConfig actionConfig) throws ClassNotFoundException,
341: IllegalAccessException, InstantiationException,
342: InvocationTargetException {
343: if (configured) {
344: throw new IllegalStateException("Configuration is frozen");
345: }
346:
347: String ancestorType = getExtends();
348:
349: if ((!extensionProcessed) && (ancestorType != null)) {
350: ExceptionConfig baseConfig = null;
351:
352: // We only check the action config if we're not a global handler
353: boolean checkActionConfig = (this != moduleConfig
354: .findExceptionConfig(getType()));
355:
356: // ... and the action config was provided
357: checkActionConfig &= (actionConfig != null);
358:
359: // ... and we're not extending a config with the same type value
360: // (because if we are, that means we're an action-level handler
361: // extending a global handler).
362: checkActionConfig &= !ancestorType.equals(getType());
363:
364: // We first check in the action config's exception handlers
365: if (checkActionConfig) {
366: baseConfig = actionConfig
367: .findExceptionConfig(ancestorType);
368: }
369:
370: // Then check the global exception handlers
371: if (baseConfig == null) {
372: baseConfig = moduleConfig
373: .findExceptionConfig(ancestorType);
374: }
375:
376: if (baseConfig == null) {
377: throw new NullPointerException("Unable to find "
378: + "handler for '" + ancestorType
379: + "' to extend.");
380: }
381:
382: // Check for circular inheritance and make sure the base config's
383: // own inheritance has been processed already
384: if (checkCircularInheritance(moduleConfig, actionConfig)) {
385: throw new IllegalArgumentException(
386: "Circular inheritance detected for forward "
387: + getType());
388: }
389:
390: if (!baseConfig.isExtensionProcessed()) {
391: baseConfig.processExtends(moduleConfig, actionConfig);
392: }
393:
394: // copy values from the base config
395: inheritFrom(baseConfig);
396: }
397:
398: extensionProcessed = true;
399: }
400:
401: /**
402: * Return a String representation of this object.
403: */
404: public String toString() {
405: StringBuffer sb = new StringBuffer("ExceptionConfig[");
406:
407: sb.append("type=");
408: sb.append(this .type);
409:
410: if (this .bundle != null) {
411: sb.append(",bundle=");
412: sb.append(this .bundle);
413: }
414:
415: if (this .inherit != null) {
416: sb.append(",extends=");
417: sb.append(this .inherit);
418: }
419:
420: sb.append(",handler=");
421: sb.append(this .handler);
422: sb.append(",key=");
423: sb.append(this .key);
424: sb.append(",path=");
425: sb.append(this .path);
426: sb.append(",scope=");
427: sb.append(this .scope);
428: sb.append("]");
429:
430: return (sb.toString());
431: }
432: }
|