001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: DTMException.java,v 1.8 2004/08/17 16:17:42 mcnamara Exp $
018: */
019: package org.apache.xml.dtm;
020:
021: import java.lang.reflect.InvocationTargetException;
022: import java.lang.reflect.Method;
023:
024: import javax.xml.transform.SourceLocator;
025:
026: import org.apache.xml.res.XMLErrorResources;
027: import org.apache.xml.res.XMLMessages;
028:
029: /**
030: * This class specifies an exceptional condition that occured
031: * in the DTM module.
032: */
033: public class DTMException extends RuntimeException {
034: static final long serialVersionUID = -775576419181334734L;
035:
036: /** Field locator specifies where the error occured.
037: * @serial */
038: SourceLocator locator;
039:
040: /**
041: * Method getLocator retrieves an instance of a SourceLocator
042: * object that specifies where an error occured.
043: *
044: * @return A SourceLocator object, or null if none was specified.
045: */
046: public SourceLocator getLocator() {
047: return locator;
048: }
049:
050: /**
051: * Method setLocator sets an instance of a SourceLocator
052: * object that specifies where an error occured.
053: *
054: * @param location A SourceLocator object, or null to clear the location.
055: */
056: public void setLocator(SourceLocator location) {
057: locator = location;
058: }
059:
060: /** Field containedException specifies a wrapped exception. May be null.
061: * @serial */
062: Throwable containedException;
063:
064: /**
065: * This method retrieves an exception that this exception wraps.
066: *
067: * @return An Throwable object, or null.
068: * @see #getCause
069: */
070: public Throwable getException() {
071: return containedException;
072: }
073:
074: /**
075: * Returns the cause of this throwable or <code>null</code> if the
076: * cause is nonexistent or unknown. (The cause is the throwable that
077: * caused this throwable to get thrown.)
078: */
079: public Throwable getCause() {
080:
081: return ((containedException == this ) ? null
082: : containedException);
083: }
084:
085: /**
086: * Initializes the <i>cause</i> of this throwable to the specified value.
087: * (The cause is the throwable that caused this throwable to get thrown.)
088: *
089: * <p>This method can be called at most once. It is generally called from
090: * within the constructor, or immediately after creating the
091: * throwable. If this throwable was created
092: * with {@link #DTMException(Throwable)} or
093: * {@link #DTMException(String,Throwable)}, this method cannot be called
094: * even once.
095: *
096: * @param cause the cause (which is saved for later retrieval by the
097: * {@link #getCause()} method). (A <tt>null</tt> value is
098: * permitted, and indicates that the cause is nonexistent or
099: * unknown.)
100: * @return a reference to this <code>Throwable</code> instance.
101: * @throws IllegalArgumentException if <code>cause</code> is this
102: * throwable. (A throwable cannot
103: * be its own cause.)
104: * @throws IllegalStateException if this throwable was
105: * created with {@link #DTMException(Throwable)} or
106: * {@link #DTMException(String,Throwable)}, or this method has already
107: * been called on this throwable.
108: */
109: public synchronized Throwable initCause(Throwable cause) {
110:
111: if ((this .containedException == null) && (cause != null)) {
112: throw new IllegalStateException(
113: XMLMessages
114: .createXMLMessage(
115: XMLErrorResources.ER_CANNOT_OVERWRITE_CAUSE,
116: null)); //"Can't overwrite cause");
117: }
118:
119: if (cause == this ) {
120: throw new IllegalArgumentException(
121: XMLMessages
122: .createXMLMessage(
123: XMLErrorResources.ER_SELF_CAUSATION_NOT_PERMITTED,
124: null)); //"Self-causation not permitted");
125: }
126:
127: this .containedException = cause;
128:
129: return this ;
130: }
131:
132: /**
133: * Create a new DTMException.
134: *
135: * @param message The error or warning message.
136: */
137: public DTMException(String message) {
138:
139: super (message);
140:
141: this .containedException = null;
142: this .locator = null;
143: }
144:
145: /**
146: * Create a new DTMException wrapping an existing exception.
147: *
148: * @param e The exception to be wrapped.
149: */
150: public DTMException(Throwable e) {
151:
152: super (e.getMessage());
153:
154: this .containedException = e;
155: this .locator = null;
156: }
157:
158: /**
159: * Wrap an existing exception in a DTMException.
160: *
161: * <p>This is used for throwing processor exceptions before
162: * the processing has started.</p>
163: *
164: * @param message The error or warning message, or null to
165: * use the message from the embedded exception.
166: * @param e Any exception
167: */
168: public DTMException(String message, Throwable e) {
169:
170: super (((message == null) || (message.length() == 0)) ? e
171: .getMessage() : message);
172:
173: this .containedException = e;
174: this .locator = null;
175: }
176:
177: /**
178: * Create a new DTMException from a message and a Locator.
179: *
180: * <p>This constructor is especially useful when an application is
181: * creating its own exception from within a DocumentHandler
182: * callback.</p>
183: *
184: * @param message The error or warning message.
185: * @param locator The locator object for the error or warning.
186: */
187: public DTMException(String message, SourceLocator locator) {
188:
189: super (message);
190:
191: this .containedException = null;
192: this .locator = locator;
193: }
194:
195: /**
196: * Wrap an existing exception in a DTMException.
197: *
198: * @param message The error or warning message, or null to
199: * use the message from the embedded exception.
200: * @param locator The locator object for the error or warning.
201: * @param e Any exception
202: */
203: public DTMException(String message, SourceLocator locator,
204: Throwable e) {
205:
206: super (message);
207:
208: this .containedException = e;
209: this .locator = locator;
210: }
211:
212: /**
213: * Get the error message with location information
214: * appended.
215: */
216: public String getMessageAndLocation() {
217:
218: StringBuffer sbuffer = new StringBuffer();
219: String message = super .getMessage();
220:
221: if (null != message) {
222: sbuffer.append(message);
223: }
224:
225: if (null != locator) {
226: String systemID = locator.getSystemId();
227: int line = locator.getLineNumber();
228: int column = locator.getColumnNumber();
229:
230: if (null != systemID) {
231: sbuffer.append("; SystemID: ");
232: sbuffer.append(systemID);
233: }
234:
235: if (0 != line) {
236: sbuffer.append("; Line#: ");
237: sbuffer.append(line);
238: }
239:
240: if (0 != column) {
241: sbuffer.append("; Column#: ");
242: sbuffer.append(column);
243: }
244: }
245:
246: return sbuffer.toString();
247: }
248:
249: /**
250: * Get the location information as a string.
251: *
252: * @return A string with location info, or null
253: * if there is no location information.
254: */
255: public String getLocationAsString() {
256:
257: if (null != locator) {
258: StringBuffer sbuffer = new StringBuffer();
259: String systemID = locator.getSystemId();
260: int line = locator.getLineNumber();
261: int column = locator.getColumnNumber();
262:
263: if (null != systemID) {
264: sbuffer.append("; SystemID: ");
265: sbuffer.append(systemID);
266: }
267:
268: if (0 != line) {
269: sbuffer.append("; Line#: ");
270: sbuffer.append(line);
271: }
272:
273: if (0 != column) {
274: sbuffer.append("; Column#: ");
275: sbuffer.append(column);
276: }
277:
278: return sbuffer.toString();
279: } else {
280: return null;
281: }
282: }
283:
284: /**
285: * Print the the trace of methods from where the error
286: * originated. This will trace all nested exception
287: * objects, as well as this object.
288: */
289: public void printStackTrace() {
290: printStackTrace(new java.io.PrintWriter(System.err, true));
291: }
292:
293: /**
294: * Print the the trace of methods from where the error
295: * originated. This will trace all nested exception
296: * objects, as well as this object.
297: * @param s The stream where the dump will be sent to.
298: */
299: public void printStackTrace(java.io.PrintStream s) {
300: printStackTrace(new java.io.PrintWriter(s));
301: }
302:
303: /**
304: * Print the the trace of methods from where the error
305: * originated. This will trace all nested exception
306: * objects, as well as this object.
307: * @param s The writer where the dump will be sent to.
308: */
309: public void printStackTrace(java.io.PrintWriter s) {
310:
311: if (s == null) {
312: s = new java.io.PrintWriter(System.err, true);
313: }
314:
315: try {
316: String locInfo = getLocationAsString();
317:
318: if (null != locInfo) {
319: s.println(locInfo);
320: }
321:
322: super .printStackTrace(s);
323: } catch (Throwable e) {
324: }
325:
326: boolean isJdk14OrHigher = false;
327: try {
328: Throwable.class.getMethod("getCause", null);
329: isJdk14OrHigher = true;
330: } catch (NoSuchMethodException nsme) {
331: // do nothing
332: }
333:
334: // The printStackTrace method of the Throwable class in jdk 1.4
335: // and higher will include the cause when printing the backtrace.
336: // The following code is only required when using jdk 1.3 or lower
337: if (!isJdk14OrHigher) {
338: Throwable exception = getException();
339:
340: for (int i = 0; (i < 10) && (null != exception); i++) {
341: s.println("---------");
342:
343: try {
344: if (exception instanceof DTMException) {
345: String locInfo = ((DTMException) exception)
346: .getLocationAsString();
347:
348: if (null != locInfo) {
349: s.println(locInfo);
350: }
351: }
352:
353: exception.printStackTrace(s);
354: } catch (Throwable e) {
355: s.println("Could not print stack trace...");
356: }
357:
358: try {
359: Method meth = ((Object) exception).getClass()
360: .getMethod("getException", null);
361:
362: if (null != meth) {
363: Throwable prev = exception;
364:
365: exception = (Throwable) meth.invoke(exception,
366: null);
367:
368: if (prev == exception) {
369: break;
370: }
371: } else {
372: exception = null;
373: }
374: } catch (InvocationTargetException ite) {
375: exception = null;
376: } catch (IllegalAccessException iae) {
377: exception = null;
378: } catch (NoSuchMethodException nsme) {
379: exception = null;
380: }
381: }
382: }
383: }
384: }
|