001: package org.apache.ojb.broker.util;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.sql.SQLException;
019: import java.sql.BatchUpdateException;
020: import java.sql.SQLWarning;
021:
022: import org.apache.commons.lang.SystemUtils;
023: import org.apache.commons.lang.exception.ExceptionUtils;
024: import org.apache.ojb.broker.KeyConstraintViolatedException;
025: import org.apache.ojb.broker.PersistenceBrokerSQLException;
026: import org.apache.ojb.broker.core.ValueContainer;
027: import org.apache.ojb.broker.metadata.ClassDescriptor;
028: import org.apache.ojb.broker.metadata.FieldDescriptor;
029: import org.apache.ojb.broker.metadata.JdbcTypesHelper;
030: import org.apache.ojb.broker.util.logging.Logger;
031:
032: /**
033: * A helper class which endorse dealing with exceptions.
034: *
035: * @version $Id: ExceptionHelper.java,v 1.2.2.3 2005/12/21 22:27:47 tomdz Exp $
036: */
037: abstract public class ExceptionHelper {
038: /**
039: * Method which support the conversion of {@link java.sql.SQLException} to
040: * OJB's runtime exception (with additional message details).
041: *
042: * @param message The error message to use, if <em>null</em> a standard message is used.
043: * @param ex The exception to convert (mandatory).
044: * @param sql The used sql-statement or <em>null</em>.
045: * @param logger The {@link org.apache.ojb.broker.util.logging.Logger} to log an detailed message
046: * to the specified {@link org.apache.ojb.broker.util.logging.Logger} or <em>null</em> to skip logging message.
047: * @return A new created {@link org.apache.ojb.broker.PersistenceBrokerSQLException} based on the specified
048: * arguments.
049: */
050: public static PersistenceBrokerSQLException generateException(
051: String message, SQLException ex, String sql, Logger logger) {
052: return generateException(message, ex, sql, null, null, logger,
053: null);
054: }
055:
056: /**
057: * Method which support the conversion of {@link java.sql.SQLException} to
058: * OJB's runtime exception (with additional message details).
059: *
060: * @param ex The exception to convert (mandatory).
061: * @param sql The used sql-statement or <em>null</em>.
062: * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the target object or <em>null</em>.
063: * @param logger The {@link org.apache.ojb.broker.util.logging.Logger} to log an detailed message
064: * to the specified {@link org.apache.ojb.broker.util.logging.Logger} or <em>null</em> to skip logging message.
065: * @param obj The target object or <em>null</em>.
066: * @return A new created {@link org.apache.ojb.broker.PersistenceBrokerSQLException} based on the specified
067: * arguments.
068: */
069: public static PersistenceBrokerSQLException generateException(
070: SQLException ex, String sql, ClassDescriptor cld,
071: Logger logger, Object obj) {
072: return generateException(ex, sql, cld, null, logger, obj);
073: }
074:
075: /**
076: * Method which support the conversion of {@link java.sql.SQLException} to
077: * OJB's runtime exception (with additional message details).
078: *
079: * @param ex The exception to convert (mandatory).
080: * @param sql The used sql-statement or <em>null</em>.
081: * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the target object or <em>null</em>.
082: * @param values The values set in prepared statement or <em>null</em>.
083: * @param logger The {@link org.apache.ojb.broker.util.logging.Logger} to log an detailed message
084: * to the specified {@link org.apache.ojb.broker.util.logging.Logger} or <em>null</em> to skip logging message.
085: * @param obj The target object or <em>null</em>.
086: * @return A new created {@link org.apache.ojb.broker.PersistenceBrokerSQLException} based on the specified
087: * arguments.
088: */
089: public static PersistenceBrokerSQLException generateException(
090: SQLException ex, String sql, ClassDescriptor cld,
091: ValueContainer[] values, Logger logger, Object obj) {
092: return generateException(null, ex, sql, cld, values, logger,
093: obj);
094: }
095:
096: /**
097: * Method which support the conversion of {@link java.sql.SQLException} to
098: * OJB's runtime exception (with additional message details).
099: *
100: * @param message The error message to use, if <em>null</em> a standard message is used.
101: * @param ex The exception to convert (mandatory).
102: * @param sql The used sql-statement or <em>null</em>.
103: * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the target object or <em>null</em>.
104: * @param values The values set in prepared statement or <em>null</em>.
105: * @param logger The {@link org.apache.ojb.broker.util.logging.Logger} to log an detailed message
106: * to the specified {@link org.apache.ojb.broker.util.logging.Logger} or <em>null</em> to skip logging message.
107: * @param obj The target object or <em>null</em>.
108: * @return A new created {@link org.apache.ojb.broker.PersistenceBrokerSQLException} based on the specified
109: * arguments.
110: */
111: public static PersistenceBrokerSQLException generateException(
112: String message, SQLException ex, String sql,
113: ClassDescriptor cld, ValueContainer[] values,
114: Logger logger, Object obj) {
115: /*
116: X/OPEN codes within class 23:
117: 23000 INTEGRITY CONSTRAINT VIOLATION
118: 23001 RESTRICT VIOLATION
119: 23502 NOT NULL VIOLATION
120: 23503 FOREIGN KEY VIOLATION
121: 23505 UNIQUE VIOLATION
122: 23514 CHECK VIOLATION
123: */
124: String eol = SystemUtils.LINE_SEPARATOR;
125: StringBuffer msg = new StringBuffer(eol);
126: eol += "* ";
127:
128: if (ex instanceof BatchUpdateException) {
129: BatchUpdateException tmp = (BatchUpdateException) ex;
130: if (message != null) {
131: msg.append("* ").append(message);
132: } else {
133: msg
134: .append("* BatchUpdateException during execution of sql-statement:");
135: }
136: msg.append(eol).append("Batch update count is '").append(
137: tmp.getUpdateCounts()).append("'");
138: } else if (ex instanceof SQLWarning) {
139: if (message != null) {
140: msg.append("* ").append(message);
141: } else {
142: msg
143: .append("* SQLWarning during execution of sql-statement:");
144: }
145: } else {
146: if (message != null) {
147: msg.append("* ").append(message);
148: } else {
149: msg
150: .append("* SQLException during execution of sql-statement:");
151: }
152: }
153:
154: if (sql != null) {
155: msg.append(eol).append("sql statement was '").append(sql)
156: .append("'");
157: }
158: String stateCode = null;
159: if (ex != null) {
160: msg.append(eol).append("Exception message is [").append(
161: ex.getMessage()).append("]");
162: msg.append(eol).append("Vendor error code [").append(
163: ex.getErrorCode()).append("]");
164: msg.append(eol).append("SQL state code [");
165:
166: stateCode = ex.getSQLState();
167: if ("23000".equalsIgnoreCase(stateCode))
168: msg.append(stateCode).append(
169: "=INTEGRITY CONSTRAINT VIOLATION");
170: else if ("23001".equalsIgnoreCase(stateCode))
171: msg.append(stateCode).append("=RESTRICT VIOLATION");
172: else if ("23502".equalsIgnoreCase(stateCode))
173: msg.append(stateCode).append("=NOT NULL VIOLATION");
174: else if ("23503".equalsIgnoreCase(stateCode))
175: msg.append(stateCode).append("=FOREIGN KEY VIOLATION");
176: else if ("23505".equalsIgnoreCase(stateCode))
177: msg.append(stateCode).append("=UNIQUE VIOLATION");
178: else if ("23514".equalsIgnoreCase(stateCode))
179: msg.append(stateCode).append("=CHECK VIOLATION");
180: else
181: msg.append(stateCode);
182: msg.append("]");
183: }
184:
185: if (cld != null) {
186: msg.append(eol).append("Target class is '").append(
187: cld.getClassNameOfObject()).append("'");
188: FieldDescriptor[] fields = cld.getPkFields();
189: msg.append(eol).append("PK of the target object is [");
190: for (int i = 0; i < fields.length; i++) {
191: try {
192: if (i > 0)
193: msg.append(", ");
194: msg
195: .append(fields[i].getPersistentField()
196: .getName());
197: if (obj != null) {
198: msg.append("=");
199: msg.append(fields[i].getPersistentField().get(
200: obj));
201: }
202: } catch (Exception ignore) {
203: msg.append(" PK field build FAILED! ");
204: }
205: }
206: msg.append("]");
207: }
208: if (values != null) {
209: msg.append(eol).append(values.length).append(
210: " values performed in statement: ").append(eol);
211: for (int i = 0; i < values.length; i++) {
212: ValueContainer value = values[i];
213: msg.append("[");
214: msg.append("jdbcType=").append(
215: JdbcTypesHelper.getSqlTypeAsString(value
216: .getJdbcType().getType()));
217: msg.append(", value=").append(value.getValue());
218: msg.append("]");
219: }
220: }
221: if (obj != null) {
222: msg.append(eol).append("Source object: ");
223: try {
224: msg.append(obj.toString());
225: } catch (Exception e) {
226: msg.append(obj.getClass());
227: }
228: }
229:
230: // message string for PB exception
231: String shortMsg = msg.toString();
232:
233: if (ex != null) {
234: // add causing stack trace
235: Throwable rootCause = ExceptionUtils.getRootCause(ex);
236: if (rootCause == null)
237: rootCause = ex;
238: msg.append(eol).append("The root stack trace is --> ");
239: String rootStack = ExceptionUtils.getStackTrace(rootCause);
240: msg.append(eol).append(rootStack);
241: }
242: msg.append(SystemUtils.LINE_SEPARATOR).append("**");
243:
244: // log error message
245: if (logger != null)
246: logger.error(msg.toString());
247:
248: // throw a specific type of runtime exception for a key constraint.
249: if ("23000".equals(stateCode) || "23505".equals(stateCode)) {
250: throw new KeyConstraintViolatedException(shortMsg, ex);
251: } else {
252: throw new PersistenceBrokerSQLException(shortMsg, ex);
253: }
254: }
255: }
|