1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you 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 /* 19 * $Id: DTMException.java 468653 2006-10-28 07:07:05Z minchau $ 20 */ 21 package org.apache.xml.dtm; 22 23 24 import java.lang.reflect.InvocationTargetException; 25 import java.lang.reflect.Method; 26 27 import javax.xml.transform.SourceLocator; 28 29 import org.apache.xml.res.XMLErrorResources; 30 import org.apache.xml.res.XMLMessages; 31 32 33 /** 34 * This class specifies an exceptional condition that occured 35 * in the DTM module. 36 */ 37 public class DTMException extends RuntimeException { 38 static final long serialVersionUID = -775576419181334734L; 39 40 /** Field locator specifies where the error occured. 41 * @serial */ 42 SourceLocator locator; 43 44 /** 45 * Method getLocator retrieves an instance of a SourceLocator 46 * object that specifies where an error occured. 47 * 48 * @return A SourceLocator object, or null if none was specified. 49 */ 50 public SourceLocator getLocator() { 51 return locator; 52 } 53 54 /** 55 * Method setLocator sets an instance of a SourceLocator 56 * object that specifies where an error occured. 57 * 58 * @param location A SourceLocator object, or null to clear the location. 59 */ 60 public void setLocator(SourceLocator location) { 61 locator = location; 62 } 63 64 /** Field containedException specifies a wrapped exception. May be null. 65 * @serial */ 66 Throwable containedException; 67 68 /** 69 * This method retrieves an exception that this exception wraps. 70 * 71 * @return An Throwable object, or null. 72 * @see #getCause 73 */ 74 public Throwable getException() { 75 return containedException; 76 } 77 78 /** 79 * Returns the cause of this throwable or <code>null</code> if the 80 * cause is nonexistent or unknown. (The cause is the throwable that 81 * caused this throwable to get thrown.) 82 */ 83 public Throwable getCause() { 84 85 return ((containedException == this) 86 ? null 87 : containedException); 88 } 89 90 /** 91 * Initializes the <i>cause</i> of this throwable to the specified value. 92 * (The cause is the throwable that caused this throwable to get thrown.) 93 * 94 * <p>This method can be called at most once. It is generally called from 95 * within the constructor, or immediately after creating the 96 * throwable. If this throwable was created 97 * with {@link #DTMException(Throwable)} or 98 * {@link #DTMException(String,Throwable)}, this method cannot be called 99 * 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", (Class<?>) 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 (Class<?>) null); 361 362 if (null != meth) { 363 Throwable prev = exception; 364 365 exception = (Throwable) meth.invoke(exception, (Class<?>) 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 } 384