1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.transform; 27 28 import java.lang.reflect.Method; 29 import java.lang.reflect.InvocationTargetException; 30 import java.security.AccessControlContext; 31 import java.security.AccessController; 32 import java.security.CodeSigner; 33 import java.security.CodeSource; 34 import java.security.PermissionCollection; 35 import java.security.Permissions; 36 import java.security.PrivilegedAction; 37 import java.security.ProtectionDomain; 38 import java.util.Objects; 39 40 /** 41 * This class specifies an exceptional condition that occurred 42 * during the transformation process. 43 */ 44 public class TransformerException extends Exception { 45 46 private static final long serialVersionUID = 975798773772956428L; 47 48 /** Field locator specifies where the error occurred */ 49 SourceLocator locator; 50 51 /** 52 * Method getLocator retrieves an instance of a SourceLocator 53 * object that specifies where an error occurred. 54 * 55 * @return A SourceLocator object, or null if none was specified. 56 */ getLocator()57 public SourceLocator getLocator() { 58 return this.locator; 59 } 60 61 /** 62 * Method setLocator sets an instance of a SourceLocator 63 * object that specifies where an error occurred. 64 * 65 * @param location A SourceLocator object, or null to clear the location. 66 */ setLocator(SourceLocator location)67 public void setLocator(SourceLocator location) { 68 this.locator = location; 69 } 70 71 /** Field containedException specifies a wrapped exception. May be null. */ 72 Throwable containedException; 73 74 /** 75 * This method retrieves an exception that this exception wraps. 76 * 77 * @return An Throwable object, or null. 78 * @see #getCause 79 */ getException()80 public Throwable getException() { 81 return containedException; 82 } 83 84 /** 85 * Returns the cause of this throwable or <code>null</code> if the 86 * cause is nonexistent or unknown. (The cause is the throwable that 87 * caused this throwable to get thrown.) 88 * @return the cause, or null if unknown 89 */ 90 @Override getCause()91 public Throwable getCause() { 92 93 return ((containedException == this) 94 ? null 95 : containedException); 96 } 97 98 /** 99 * Initializes the <i>cause</i> of this throwable to the specified value. 100 * (The cause is the throwable that caused this throwable to get thrown.) 101 * 102 * <p>This method can be called at most once. It is generally called from 103 * within the constructor, or immediately after creating the 104 * throwable. If this throwable was created 105 * with {@link #TransformerException(Throwable)} or 106 * {@link #TransformerException(String,Throwable)}, this method cannot be called 107 * even once. 108 * 109 * @param cause the cause (which is saved for later retrieval by the 110 * {@link #getCause()} method). (A <code>null</code> value is 111 * permitted, and indicates that the cause is nonexistent or 112 * unknown.) 113 * @return a reference to this <code>Throwable</code> instance. 114 * @throws IllegalArgumentException if <code>cause</code> is this 115 * throwable. (A throwable cannot 116 * be its own cause.) 117 * @throws IllegalStateException if this throwable was 118 * created with {@link #TransformerException(Throwable)} or 119 * {@link #TransformerException(String,Throwable)}, or this method has already 120 * been called on this throwable. 121 */ 122 @Override initCause(Throwable cause)123 public synchronized Throwable initCause(Throwable cause) { 124 125 if (this.containedException != null) { 126 throw new IllegalStateException("Can't overwrite cause"); 127 } 128 129 if (cause == this) { 130 throw new IllegalArgumentException( 131 "Self-causation not permitted"); 132 } 133 134 this.containedException = cause; 135 136 return this; 137 } 138 139 /** 140 * Create a new TransformerException. 141 * 142 * @param message The error or warning message. 143 */ TransformerException(String message)144 public TransformerException(String message) { 145 this(message, null, null); 146 } 147 148 /** 149 * Create a new TransformerException wrapping an existing exception. 150 * 151 * @param e The exception to be wrapped. 152 */ TransformerException(Throwable e)153 public TransformerException(Throwable e) { 154 this(null, null, e); 155 } 156 157 /** 158 * Wrap an existing exception in a TransformerException. 159 * 160 * <p>This is used for throwing processor exceptions before 161 * the processing has started.</p> 162 * 163 * @param message The error or warning message, or null to 164 * use the message from the embedded exception. 165 * @param e Any exception 166 */ TransformerException(String message, Throwable e)167 public TransformerException(String message, Throwable e) { 168 this(message, null, e); 169 } 170 171 /** 172 * Create a new TransformerException from a message and a Locator. 173 * 174 * <p>This constructor is especially useful when an application is 175 * creating its own exception from within a DocumentHandler 176 * callback.</p> 177 * 178 * @param message The error or warning message. 179 * @param locator The locator object for the error or warning. 180 */ TransformerException(String message, SourceLocator locator)181 public TransformerException(String message, SourceLocator locator) { 182 this(message, locator, null); 183 } 184 185 /** 186 * Wrap an existing exception in a TransformerException. 187 * 188 * @param message The error or warning message, or null to 189 * use the message from the embedded exception. 190 * @param locator The locator object for the error or warning. 191 * @param e Any exception 192 */ TransformerException(String message, SourceLocator locator, Throwable e)193 public TransformerException(String message, SourceLocator locator, 194 Throwable e) { 195 super(((message == null) || (message.length() == 0)) 196 ? ((e == null) ? "" : e.toString()) 197 : message); 198 199 this.containedException = e; 200 this.locator = locator; 201 } 202 203 /** 204 * Get the error message with location information 205 * appended. 206 * 207 * @return A <code>String</code> representing the error message with 208 * location information appended. 209 */ getMessageAndLocation()210 public String getMessageAndLocation() { 211 StringBuilder sbuffer = new StringBuilder(); 212 sbuffer.append(Objects.toString(super.getMessage(), "")); 213 sbuffer.append(Objects.toString(getLocationAsString(), "")); 214 215 return sbuffer.toString(); 216 } 217 218 /** 219 * Get the location information as a string. 220 * 221 * @return A string with location info, or null 222 * if there is no location information. 223 */ getLocationAsString()224 public String getLocationAsString() { 225 if (locator == null) { 226 return null; 227 } 228 229 if (System.getSecurityManager() == null) { 230 return getLocationString(); 231 } else { 232 return (String) AccessController.doPrivileged( 233 new PrivilegedAction<String>() { 234 public String run() { 235 return getLocationString(); 236 } 237 }, 238 new AccessControlContext(new ProtectionDomain[] {getNonPrivDomain()}) 239 ); 240 } 241 } 242 243 /** 244 * Constructs the location string. 245 * @return the location string 246 */ 247 private String getLocationString() { 248 if (locator == null) { 249 return null; 250 } 251 252 StringBuilder sbuffer = new StringBuilder(); 253 String systemID = locator.getSystemId(); 254 int line = locator.getLineNumber(); 255 int column = locator.getColumnNumber(); 256 257 if (null != systemID) { 258 sbuffer.append("; SystemID: "); 259 sbuffer.append(systemID); 260 } 261 262 if (0 != line) { 263 sbuffer.append("; Line#: "); 264 sbuffer.append(line); 265 } 266 267 if (0 != column) { 268 sbuffer.append("; Column#: "); 269 sbuffer.append(column); 270 } 271 272 return sbuffer.toString(); 273 } 274 275 /** 276 * Print the the trace of methods from where the error 277 * originated. This will trace all nested exception 278 * objects, as well as this object. 279 */ 280 @Override 281 public void printStackTrace() { 282 printStackTrace(new java.io.PrintWriter(System.err, true)); 283 } 284 285 /** 286 * Print the the trace of methods from where the error 287 * originated. This will trace all nested exception 288 * objects, as well as this object. 289 * @param s The stream where the dump will be sent to. 290 */ 291 @Override 292 public void printStackTrace(java.io.PrintStream s) { 293 printStackTrace(new java.io.PrintWriter(s)); 294 } 295 296 /** 297 * Print the the trace of methods from where the error 298 * originated. This will trace all nested exception 299 * objects, as well as this object. 300 * @param s The writer where the dump will be sent to. 301 */ 302 @Override 303 public void printStackTrace(java.io.PrintWriter s) { 304 305 if (s == null) { 306 s = new java.io.PrintWriter(System.err, true); 307 } 308 309 try { 310 String locInfo = getLocationAsString(); 311 312 if (null != locInfo) { 313 s.println(locInfo); 314 } 315 316 super.printStackTrace(s); 317 } catch (Throwable e) {} 318 319 Throwable exception = getException(); 320 321 for (int i = 0; (i < 10) && (null != exception); i++) { 322 s.println("---------"); 323 324 try { 325 if (exception instanceof TransformerException) { 326 String locInfo = 327 ((TransformerException) exception) 328 .getLocationAsString(); 329 330 if (null != locInfo) { 331 s.println(locInfo); 332 } 333 } 334 335 exception.printStackTrace(s); 336 } catch (Throwable e) { 337 s.println("Could not print stack trace..."); 338 } 339 340 try { 341 Method meth = 342 ((Object) exception).getClass().getMethod("getException", 343 (Class[]) null); 344 345 if (null != meth) { 346 Throwable prev = exception; 347 348 exception = (Throwable) meth.invoke(exception, (Object[]) null); 349 350 if (prev == exception) { 351 break; 352 } 353 } else { 354 exception = null; 355 } 356 } catch (InvocationTargetException | IllegalAccessException 357 | NoSuchMethodException e) { 358 exception = null; 359 } 360 } 361 // insure output is written 362 s.flush(); 363 } 364 365 /** 366 * Creates a ProtectionDomain that has no permission. 367 * @return a ProtectionDomain 368 */ 369 private ProtectionDomain getNonPrivDomain() { 370 CodeSource nullSource = new CodeSource(null, (CodeSigner[]) null); 371 PermissionCollection noPermission = new Permissions(); 372 return new ProtectionDomain(nullSource, noPermission); 373 } 374 } 375