View Javadoc

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