View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  /*
19   * JDOException.java
20   *
21   */
22  
23  package javax.jdo;
24  
25  import javax.jdo.spi.I18NHelper;
26  
27  /** This is the root of all JDO Exceptions.  It contains an optional detail
28   * message, an optional nested <code>Throwable</code> array and an optional failed object.
29   * @author Craig Russell
30   * @version 1.0.2
31   */
32  public class JDOException extends java.lang.RuntimeException {
33    
34    /** This exception was generated because of an exception in the runtime library.
35     * @serial the nested <code>Throwable</code> array
36     */
37    Throwable[] nested;
38    
39    /** This exception may be the result of incorrect parameters supplied
40     * to an API.  This is the object from which the user can determine
41     * the cause of the problem.
42     * @serial the failed <code>Object</code>
43     */
44    Object failed;
45  
46      /** The Internationalization message helper.
47       */
48      private static I18NHelper msg = I18NHelper.getInstance ("javax.jdo.Bundle"); //NOI18N
49  
50      /** Flag indicating whether printStackTrace is being executed.
51       */
52      private boolean inPrintStackTrace = false;
53      
54    /**
55     * Constructs a new <code>JDOException</code> without a detail message.
56     */
57    public JDOException() {
58    }
59    
60  
61    /**
62     * Constructs a new <code>JDOException</code> with the specified detail message.
63     * @param msg the detail message.
64     */
65    public JDOException(String msg) {
66      super(msg);
67    }
68  
69    /** Constructs a new <code>JDOException</code> with the specified detail message
70     * and nested <code>Throwable</code>s.
71     * @param msg the detail message.
72     * @param nested the nested <code>Throwable[]</code>.
73     */
74    public JDOException(String msg, Throwable[] nested) {
75      super(msg);
76      this.nested = nested;
77    }
78    
79    /** Constructs a new <code>JDOException</code> with the specified detail message
80     * and nested <code>Throwable</code>.
81     * @param msg the detail message.
82     * @param nested the nested <code>Throwable</code>.
83     */
84    public JDOException(String msg, Throwable nested) {
85      super(msg);
86      this.nested = new Throwable[] {nested};
87    }
88    
89    /** Constructs a new <code>JDOException</code> with the specified detail message
90     * and failed object.
91     * @param msg the detail message.
92     * @param failed the failed object.
93     */
94    public JDOException(String msg, Object failed) {
95      super(msg);
96      this.failed = failed;
97    }
98    
99    /** Constructs a new <code>JDOException</code> with the specified detail message,
100    * nested <code>Throwable</code>s, and failed object.
101    * @param msg the detail message.
102    * @param nested the nested <code>Throwable[]</code>.
103    * @param failed the failed object.
104    */
105   public JDOException(String msg, Throwable[] nested, Object failed) {
106     super(msg);
107     this.nested = nested;
108     this.failed = failed;
109   }
110   
111   /** Constructs a new <code>JDOException</code> with the specified detail message,
112    * nested <code>Throwable</code>, and failed object.
113    * @param msg the detail message.
114    * @param nested the nested <code>Throwable</code>.
115    * @param failed the failed object.
116    */
117   public JDOException(String msg, Throwable nested, Object failed) {
118     super(msg);
119     this.nested = new Throwable[] {nested};
120     this.failed = failed;
121   }
122   
123   /** The exception may include a failed object.
124    * @return the failed object.
125    */
126   public Object getFailedObject() {
127     return failed;
128   }
129   
130   /** The exception may have been caused by multiple exceptions in the runtime.
131    * If multiple objects caused the problem, each failed object will have
132    * its own <code>Exception</code>.
133    * @return the nested Throwable array.
134    */
135   public Throwable[] getNestedExceptions() {
136     return nested;
137   }
138   
139   /** Often there is only one nested exception, and this method returns it.
140    * If there are more than one, then this method returns the first nested
141    * exception. If there is no nested exception, then null is returned.
142    * @return the first or only nested Throwable.
143    * @since 1.0.1
144    */
145   public synchronized Throwable getCause() {
146       // super.printStackTrace calls getCause to handle the cause. 
147       // Returning null prevents the superclass from handling the cause;
148       // instead the local implementation of printStackTrace should
149       // handle the cause. Otherwise, the cause is printed twice.
150       if (nested == null || nested.length == 0 || inPrintStackTrace) {
151           return null;
152       } else {
153           return nested[0];
154       }
155   }
156   
157   /** JDK 1.4 includes a new chaining mechanism for Throwable, but since
158    * JDO has its own "legacy" chaining mechanism, the "standard" mechanism
159    * cannot be used. This method always throws a JDOFatalInternalException.
160    * @param cause ignored.
161    * @return never.
162    */
163   public Throwable initCause(Throwable cause) {
164       throw new JDOFatalInternalException(msg.msg("ERR_CannotInitCause"));
165   }
166   
167   /** The <code>String</code> representation includes the name of the class,
168    * the descriptive comment (if any),
169    * the <code>String</code> representation of the failed <code>Object</code> (if any),
170    * and the <code>String</code> representation of the nested <code>Throwable</code>s (if any).
171    * @return the <code>String</code>.
172    */
173   public synchronized String toString() {
174     int len = nested==null?0:nested.length;
175     // calculate approximate size of the String to return
176     StringBuffer sb = new StringBuffer (10 + 100 * len);
177     sb.append (super.toString());
178     // include failed object information
179     if (failed != null) {
180         sb.append ("\n").append (msg.msg ("MSG_FailedObject"));
181       String failedToString = null;
182       try {
183           failedToString = failed.toString();
184       } catch (Exception ex) {
185           // include the information from the exception thrown by failed.toString
186           Object objectId = JDOHelper.getObjectId(failed);
187           if (objectId == null) {
188               failedToString = msg.msg("MSG_ExceptionGettingFailedToString", //NOI18N
189                                        exceptionToString(ex));
190           }
191           else {
192               // include the ObjectId information
193               String objectIdToString = null;
194               try {
195                   objectIdToString = objectId.toString();
196               }
197               catch (Exception ex2) {
198                   objectIdToString = exceptionToString(ex2);
199               }
200               failedToString = msg.msg("MSG_ExceptionGettingFailedToStringObjectId", //NOI18N
201                                        exceptionToString(ex), objectIdToString);
202           }
203       }
204       sb.append (failedToString);
205     }
206     // include nested Throwable information, but only if not called by
207     // printStackTrace; the stacktrace will include the cause anyway.
208     if (len > 0 && !inPrintStackTrace) {
209       sb.append ("\n").append (msg.msg ("MSG_NestedThrowables")).append ("\n");
210       Throwable exception = nested[0];
211       sb.append (exception==null?"null":exception.toString()); //NOI18N
212       for (int i=1; i<len; ++i) {
213         sb.append ("\n"); //NOI18N
214         exception = nested[i];
215       sb.append (exception==null?"null":exception.toString()); //NOI18N
216       }
217     }
218     return sb.toString();
219   }    
220   
221     /**
222      * Prints this <code>JDOException</code> and its backtrace to the 
223      * standard error output.
224      * Print nested Throwables' stack trace as well.
225      */
226     public void printStackTrace() { 
227         printStackTrace (System.err);
228     }
229 
230     /**
231      * Prints this <code>JDOException</code> and its backtrace to the 
232      * specified print stream.
233      * Print nested Throwables' stack trace as well.
234      * @param s <code>PrintStream</code> to use for output
235      */
236     public synchronized void printStackTrace(java.io.PrintStream s) { 
237     int len = nested==null?0:nested.length;
238         synchronized (s) {
239             inPrintStackTrace = true;
240             super.printStackTrace(s);
241             if (len > 0) {
242                 s.println (msg.msg ("MSG_NestedThrowablesStackTrace"));
243                 for (int i=0; i<len; ++i) {
244                     Throwable exception = nested[i];
245                     if (exception != null) {
246                         exception.printStackTrace(s);
247                     }
248                 }
249             }
250             inPrintStackTrace = false;
251         }
252     }
253 
254     /**
255      * Prints this <code>JDOException</code> and its backtrace to the specified
256      * print writer.
257      * Print nested Throwables' stack trace as well.
258      * @param s <code>PrintWriter</code> to use for output
259      */
260     public synchronized void printStackTrace(java.io.PrintWriter s) { 
261     int len = nested==null?0:nested.length;
262         synchronized (s) {
263             inPrintStackTrace = true;
264             super.printStackTrace(s);
265             if (len > 0) {
266                 s.println (msg.msg ("MSG_NestedThrowablesStackTrace"));
267                 for (int i=0; i<len; ++i) {
268                     Throwable exception = nested[i];
269                     if (exception != null) {
270                         exception.printStackTrace(s);
271                     }
272                 }
273             }
274             inPrintStackTrace = false;
275         }
276     }
277 
278     /**
279      * Helper method returning a short description of the exception passed
280      * as an argument. The returned string has the format defined by
281      * Throwable.toString. If the exception has a non-null detail message 
282      * string, then it returns the name of exception class concatenated
283      * with ": " concatenated with the detailed message. Otherwise it
284      * returns the name of exception class.
285      * @param ex the exception to be represented.
286      * @return a string representation of the exception passed as an argument.
287      */
288     private static String exceptionToString(Exception ex)
289     {
290         if (ex == null) return null;
291         String s = ex.getClass().getName();
292         String message = ex.getMessage();
293         return (message != null) ? (s + ": " + message) : s;
294     }
295 }
296