001: /*
002: * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package java.sql;
027:
028: import java.util.Iterator;
029: import java.util.NoSuchElementException;
030: import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
031:
032: /**
033: * <P>An exception that provides information on a database access
034: * error or other errors.
035: *
036: * <P>Each <code>SQLException</code> provides several kinds of information:
037: * <UL>
038: * <LI> a string describing the error. This is used as the Java Exception
039: * message, available via the method <code>getMesasge</code>.
040: * <LI> a "SQLstate" string, which follows either the XOPEN SQLstate conventions
041: * or the SQL:2003 conventions.
042: * The values of the SQLState string are described in the appropriate spec.
043: * The <code>DatabaseMetaData</code> method <code>getSQLStateType</code>
044: * can be used to discover whether the driver returns the XOPEN type or
045: * the SQL:2003 type.
046: * <LI> an integer error code that is specific to each vendor. Normally this will
047: * be the actual error code returned by the underlying database.
048: * <LI> a chain to a next Exception. This can be used to provide additional
049: * error information.
050: * <LI> the causal relationship, if any for this <code>SQLException</code>.
051: * </UL>
052: */
053: public class SQLException extends java.lang.Exception implements
054: Iterable<Throwable> {
055:
056: /**
057: * Constructs a <code>SQLException</code> object with a given
058: * <code>reason</code>, <code>SQLState</code> and
059: * <code>vendorCode</code>.
060: *
061: * The <code>cause</code> is not initialized, and may subsequently be
062: * initialized by a call to the
063: * {@link Throwable#initCause(java.lang.Throwable)} method.
064: * <p>
065: * @param reason a description of the exception
066: * @param SQLState an XOPEN or SQL:2003 code identifying the exception
067: * @param vendorCode a database vendor-specific exception code
068: */
069: public SQLException(String reason, String SQLState, int vendorCode) {
070: super (reason);
071: this .SQLState = SQLState;
072: this .vendorCode = vendorCode;
073: if (!(this instanceof SQLWarning)) {
074: if (DriverManager.getLogWriter() != null) {
075: DriverManager.println("SQLState(" + SQLState
076: + ") vendor code(" + vendorCode + ")");
077: printStackTrace(DriverManager.getLogWriter());
078: }
079: }
080: }
081:
082: /**
083: * Constructs a <code>SQLException</code> object with a given
084: * <code>reason</code> and <code>SQLState</code>.
085: *
086: * The <code>cause</code> is not initialized, and may subsequently be
087: * initialized by a call to the
088: * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
089: * is initialized to 0.
090: * <p>
091: * @param reason a description of the exception
092: * @param SQLState an XOPEN or SQL:2003 code identifying the exception
093: */
094: public SQLException(String reason, String SQLState) {
095: super (reason);
096: this .SQLState = SQLState;
097: this .vendorCode = 0;
098: if (!(this instanceof SQLWarning)) {
099: if (DriverManager.getLogWriter() != null) {
100: printStackTrace(DriverManager.getLogWriter());
101: DriverManager.println("SQLException: SQLState("
102: + SQLState + ")");
103: }
104: }
105: }
106:
107: /**
108: * Constructs a <code>SQLException</code> object with a given
109: * <code>reason</code>. The <code>SQLState</code> is initialized to
110: * <code>null</code> and the vender code is initialized to 0.
111: *
112: * The <code>cause</code> is not initialized, and may subsequently be
113: * initialized by a call to the
114: * {@link Throwable#initCause(java.lang.Throwable)} method.
115: * <p>
116: * @param reason a description of the exception
117: */
118: public SQLException(String reason) {
119: super (reason);
120: this .SQLState = null;
121: this .vendorCode = 0;
122: if (!(this instanceof SQLWarning)) {
123: if (DriverManager.getLogWriter() != null) {
124: printStackTrace(DriverManager.getLogWriter());
125: }
126: }
127: }
128:
129: /**
130: * Constructs a <code>SQLException</code> object.
131: * The <code>reason</code>, <code>SQLState</code> are initialized
132: * to <code>null</code> and the vendor code is initialized to 0.
133: *
134: * The <code>cause</code> is not initialized, and may subsequently be
135: * initialized by a call to the
136: * {@link Throwable#initCause(java.lang.Throwable)} method.
137: * <p>
138: */
139: public SQLException() {
140: super ();
141: this .SQLState = null;
142: this .vendorCode = 0;
143: if (!(this instanceof SQLWarning)) {
144: if (DriverManager.getLogWriter() != null) {
145: printStackTrace(DriverManager.getLogWriter());
146: }
147: }
148: }
149:
150: /**
151: * Constructs a <code>SQLException</code> object with a given
152: * <code>cause</code>.
153: * The <code>SQLState</code> is initialized
154: * to <code>null</code> and the vendor code is initialized to 0.
155: * The <code>reason</code> is initialized to <code>null</code> if
156: * <code>cause==null</code> or to <code>cause.toString()</code> if
157: * <code>cause!=null</code>.
158: * <p>
159: * @param cause the underlying reason for this <code>SQLException</code>
160: * (which is saved for later retrieval by the <code>getCause()</code> method);
161: * may be null indicating the cause is non-existent or unknown.
162: * @since 1.6
163: */
164: public SQLException(Throwable cause) {
165: super (cause);
166:
167: if (!(this instanceof SQLWarning)) {
168: if (DriverManager.getLogWriter() != null) {
169: printStackTrace(DriverManager.getLogWriter());
170: }
171: }
172: }
173:
174: /**
175: * Constructs a <code>SQLException</code> object with a given
176: * <code>reason</code> and <code>cause</code>.
177: * The <code>SQLState</code> is initialized to <code>null</code>
178: * and the vendor code is initialized to 0.
179: * <p>
180: * @param reason a description of the exception.
181: * @param cause the underlying reason for this <code>SQLException</code>
182: * (which is saved for later retrieval by the <code>getCause()</code> method);
183: * may be null indicating the cause is non-existent or unknown.
184: * @since 1.6
185: */
186: public SQLException(String reason, Throwable cause) {
187: super (reason, cause);
188:
189: if (!(this instanceof SQLWarning)) {
190: if (DriverManager.getLogWriter() != null) {
191: printStackTrace(DriverManager.getLogWriter());
192: }
193: }
194: }
195:
196: /**
197: * Constructs a <code>SQLException</code> object with a given
198: * <code>reason</code>, <code>SQLState</code> and <code>cause</code>.
199: * The vendor code is initialized to 0.
200: * <p>
201: * @param reason a description of the exception.
202: * @param sqlState an XOPEN or SQL:2003 code identifying the exception
203: * @param cause the underlying reason for this <code>SQLException</code>
204: * (which is saved for later retrieval by the
205: * <code>getCause()</code> method); may be null indicating
206: * the cause is non-existent or unknown.
207: * @since 1.6
208: */
209: public SQLException(String reason, String sqlState, Throwable cause) {
210: super (reason, cause);
211:
212: this .SQLState = sqlState;
213: this .vendorCode = 0;
214: if (!(this instanceof SQLWarning)) {
215: if (DriverManager.getLogWriter() != null) {
216: printStackTrace(DriverManager.getLogWriter());
217: DriverManager.println("SQLState(" + SQLState + ")");
218: }
219: }
220: }
221:
222: /**
223: * Constructs a <code>SQLException</code> object with a given
224: * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
225: * and <code>cause</code>.
226: * <p>
227: * @param reason a description of the exception
228: * @param sqlState an XOPEN or SQL:2003 code identifying the exception
229: * @param vendorCode a database vendor-specific exception code
230: * @param cause the underlying reason for this <code>SQLException</code>
231: * (which is saved for later retrieval by the <code>getCause()</code> method);
232: * may be null indicating the cause is non-existent or unknown.
233: * @since 1.6
234: */
235: public SQLException(String reason, String sqlState, int vendorCode,
236: Throwable cause) {
237: super (reason, cause);
238:
239: this .SQLState = sqlState;
240: this .vendorCode = vendorCode;
241: if (!(this instanceof SQLWarning)) {
242: if (DriverManager.getLogWriter() != null) {
243: DriverManager.println("SQLState(" + SQLState
244: + ") vendor code(" + vendorCode + ")");
245: printStackTrace(DriverManager.getLogWriter());
246: }
247: }
248: }
249:
250: /**
251: * Retrieves the SQLState for this <code>SQLException</code> object.
252: *
253: * @return the SQLState value
254: */
255: public String getSQLState() {
256: return (SQLState);
257: }
258:
259: /**
260: * Retrieves the vendor-specific exception code
261: * for this <code>SQLException</code> object.
262: *
263: * @return the vendor's error code
264: */
265: public int getErrorCode() {
266: return (vendorCode);
267: }
268:
269: /**
270: * Retrieves the exception chained to this
271: * <code>SQLException</code> object by setNextException(SQLException ex).
272: *
273: * @return the next <code>SQLException</code> object in the chain;
274: * <code>null</code> if there are none
275: * @see #setNextException
276: */
277: public SQLException getNextException() {
278: return (next);
279: }
280:
281: /**
282: * Adds an <code>SQLException</code> object to the end of the chain.
283: *
284: * @param ex the new exception that will be added to the end of
285: * the <code>SQLException</code> chain
286: * @see #getNextException
287: */
288: public void setNextException(SQLException ex) {
289:
290: SQLException current = this ;
291: for (;;) {
292: SQLException next = current.next;
293: if (next != null) {
294: current = next;
295: continue;
296: }
297:
298: if (nextUpdater.compareAndSet(current, null, ex)) {
299: return;
300: }
301: current = current.next;
302: }
303: }
304:
305: /**
306: * Returns an iterator over the chained SQLExceptions. The iterator will
307: * be used to iterate over each SQLException and its underlying cause
308: * (if any).
309: *
310: * @return an iterator over the chained SQLExceptions and causes in the proper
311: * order
312: *
313: * @since 1.6
314: */
315: public Iterator<Throwable> iterator() {
316:
317: return new Iterator<Throwable>() {
318:
319: SQLException firstException = SQLException.this ;
320: SQLException nextException = firstException
321: .getNextException();
322: Throwable cause = firstException.getCause();
323:
324: public boolean hasNext() {
325: if (firstException != null || nextException != null
326: || cause != null)
327: return true;
328: return false;
329: }
330:
331: public Throwable next() {
332: Throwable throwable = null;
333: if (firstException != null) {
334: throwable = firstException;
335: firstException = null;
336: } else if (cause != null) {
337: throwable = cause;
338: cause = cause.getCause();
339: } else if (nextException != null) {
340: throwable = nextException;
341: cause = nextException.getCause();
342: nextException = nextException.getNextException();
343: } else
344: throw new NoSuchElementException();
345: return throwable;
346: }
347:
348: public void remove() {
349: throw new UnsupportedOperationException();
350: }
351:
352: };
353:
354: }
355:
356: /**
357: * @serial
358: */
359: private String SQLState;
360:
361: /**
362: * @serial
363: */
364: private int vendorCode;
365:
366: /**
367: * @serial
368: */
369: private volatile SQLException next;
370:
371: private static final AtomicReferenceFieldUpdater<SQLException, SQLException> nextUpdater = AtomicReferenceFieldUpdater
372: .newUpdater(SQLException.class, SQLException.class, "next");
373:
374: private static final long serialVersionUID = 2135244094396331484L;
375: }
|