001: /*
002: * $Id: AxionException.java,v 1.9 2005/04/07 19:32:00 rwald Exp $
003: * =======================================================================
004: * Copyright (c) 2002-2005 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040:
041: package org.axiondb;
042:
043: import java.io.IOException;
044: import java.io.InputStream;
045: import java.util.PropertyResourceBundle;
046:
047: /**
048: * Root exception for Axion related or specific problems. This exception provides access
049: * to Axion-specific SQL Vendor codes. Where possible they are mapped to SQL99 / XOPEN 99
050: * SQL state codes.
051: * <p>
052: * SQLState codes consisti of 5 characters. The first 2 characters specify the error
053: * class, the last three characters specify the subclass. For example, the SQLSTATE value
054: * '22012' consists of class code 22 (data exception) and subclass code 012 (division by
055: * zero). * Each of the five characters in a SQLSTATE value is a digit (0..9) or an
056: * uppercase Latin letter (A..Z).
057: * <p>
058: * Class codes that begin with a digit in the range 0..4 or a letter in the range A..H are
059: * reserved for predefined conditions. Within predefined classes, subclass codes that
060: * begin with a digit in the range 0..4 or a letter in the range A..H are reserved for
061: * predefined sub-conditions. All other subclass codes are reserved for
062: * implementation-defined sub-conditions. (see ANSI-SQL99 specification).
063: *
064: * @see {@link org.axiondb.util.ExceptionConverter}
065: * @version $Revision: 1.9 $ $Date: 2005/04/07 19:32:00 $
066: * @author Rodney Waldhoff
067: */
068: public class AxionException extends Exception {
069: public final static int DEFAULT_VENDOR_CODE = 99999; //catch-all
070: protected static PropertyResourceBundle _bundle = null;
071:
072: /**
073: * Equivalent to
074: * {@link #AxionException(java.lang.String,java.lang.Throwable) AxionException(null,null,DEFAULT_VENDOR_CODE)}.
075: */
076: public AxionException() {
077: this (null, null, DEFAULT_VENDOR_CODE);
078: }
079:
080: /**
081: * Equivalent to
082: * {@link #AxionException(java.lang.String,java.lang.Throwable,int) AxionException(null,null,vendorcode)}.
083: */
084: public AxionException(int vendorcode) {
085: this (null, null, vendorcode);
086: }
087:
088: /**
089: * Equivalent to
090: * {@link #AxionException(java.lang.String,java.lang.Throwable,int) AxionException(message,null,DEFAULT_VENDOR_CODE)}.
091: */
092: public AxionException(String message) {
093: this (message, null, DEFAULT_VENDOR_CODE);
094: }
095:
096: /**
097: * Equivalent to
098: * {@link #AxionException(java.lang.String,java.lang.Throwable,int) AxionException(message,null,vendorcode)}.
099: */
100: public AxionException(String message, int vendorcode) {
101: this (message, null, vendorcode);
102: }
103:
104: /**
105: * Construct a new {@link AxionException}with the given <i>message </i>, wrapping the
106: * given {@link Throwable}.
107: *
108: * @param message my detailed message (possibly <code>null</code>)
109: * @param nested a {@link Throwable}to wrap (possibly <code>null</code>)
110: * @param vendorcode an error code
111: */
112: public AxionException(String message, Throwable nested,
113: int vendorcode) {
114: super (null == message ? (null == nested ? null : nested
115: .toString()) : (null == nested ? message : message
116: + " (" + nested.toString() + ")"));
117: _nested = nested;
118: _vendorCode = vendorcode;
119: }
120:
121: /**
122: * Equivalent to
123: * {@link #AxionException(java.lang.String,java.lang.Throwable) AxionException(message,nested,DEFAULT_VENDOR_CODE)}.
124: */
125: public AxionException(String message, Throwable nested) {
126: this (message, nested, DEFAULT_VENDOR_CODE);
127: }
128:
129: /**
130: * Equivalent to
131: * {@link #AxionException(java.lang.String,java.lang.Throwable) AxionException(null,nested,DEFAULT_VENDOR_CODE)}.
132: */
133: public AxionException(Throwable nested) {
134: this (null, nested, DEFAULT_VENDOR_CODE);
135: }
136:
137: /**
138: * Equivalent to
139: * {@link #AxionException(java.lang.String,java.lang.Throwable) AxionException(null,nested,vendorcode)}.
140: */
141: public AxionException(Throwable nested, int vendorcode) {
142: this (null, nested, vendorcode);
143: }
144:
145: /** Returns the Axion-specific vendor code for this exception */
146: public int getVendorCode() {
147: return _vendorCode;
148: }
149:
150: /** Returns the detail message string of this AxionException */
151: public String getMessage() {
152: if (super .getMessage() != null) {
153: return super .getMessage();
154: }
155: // Load other Error code translations from a properties file
156: return getErrorMessage(_vendorCode);
157: }
158:
159: /**
160: * Returns the five-digit SQL State code (as defined in the ANSI-SQL 99 standard). The
161: * translation works as follows:
162: * <p>-- any vendor code lower than 100000 is just converted to a String.
163: * <p>-- vendor codes 10000 and over use the following rules: a) first digit
164: * indicates the position of a non-digit character.
165: * <p>
166: * <li>1: Second Class Digit is Alphanumeric (e.g. SQL StateCode "0Z001")
167: * <li>2: Last Subclass Digit is Alphanumeric (e.g. "2200E")
168: * <li>3: Second Class Digit and Last Subclass Digit are alphanumeric
169: * <li>4: Other case (e.g. for class HZ) --> explicit conversion value (must be
170: * assigned directly in code) b) Alpha Character is translated into its position in
171: * the Alphabet (e.g. H=08; Z=26) etc. thus 1026001 is translated into 0Z001 32080001
172: * would be translated into 2H00A
173: */
174: public String getSQLState() {
175: String sqlstate;
176: if (_vendorCode < 100000) {
177: sqlstate = String.valueOf(_vendorCode);
178: while (sqlstate.length() < 5) { //leftpad with zeros
179: sqlstate = '0' + sqlstate;
180: }
181: return sqlstate;
182: }
183:
184: final String CONVERSION_ERROR = "99099";
185: sqlstate = String.valueOf(_vendorCode);
186: if (sqlstate.charAt(0) > '3') { //special cases that can not be calculated
187: if (_vendorCode == 499000) {
188: return "HZ000";
189: }
190: return CONVERSION_ERROR;
191: }
192:
193: // transform last two digits of class into a character
194: if (sqlstate.charAt(0) == '1' || sqlstate.charAt(0) == '3') {
195: int charnum = Integer.parseInt(sqlstate.substring(2, 4));
196: sqlstate = sqlstate.substring(0, 2) + (char) (64 + charnum)
197: + sqlstate.substring(4, sqlstate.length());
198: }
199:
200: //transform last two digits of subclass into a character
201: if (sqlstate.charAt(0) == '2' || sqlstate.charAt(1) == '3') {
202: int charnum = Integer.parseInt(sqlstate.substring(sqlstate
203: .length() - 2, sqlstate.length()));
204: sqlstate = sqlstate.substring(0, 5) + (char) (64 + charnum);
205: }
206: sqlstate = sqlstate.substring(1, sqlstate.length());
207:
208: return sqlstate;
209: }
210:
211: private static String getErrorMessage(int vendorcode) {
212: try {
213: if (_bundle == null) {
214: getResourceBundle("org/axiondb/AxionStateCodes.properties");
215: }
216: return _bundle.getString(String.valueOf(vendorcode));
217: } catch (Exception e) {
218: return "-- Unknown Exception (" + vendorcode + ") --";
219: }
220: }
221:
222: private static void getResourceBundle(String bundleFile)
223: throws IOException {
224: ClassLoader cl = AxionException.class.getClassLoader();
225: InputStream in = null;
226: try {
227: in = cl.getResourceAsStream(bundleFile);
228: _bundle = new PropertyResourceBundle(in);
229: } finally {
230: in.close();
231: }
232: }
233:
234: /**
235: * Return the {@link Throwable}I'm wrapping, if any.
236: *
237: * @return the {@link Throwable}I'm wrapping, if any.
238: */
239: public Throwable getNestedThrowable() {
240: return _nested;
241: }
242:
243: private Throwable _nested = null;
244: private int _vendorCode;
245: }
|