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