Home | History | Annotate | Download | only in dtm
      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