1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.jdbc.sql;
20
21 import java.sql.SQLException;
22 import java.util.LinkedList;
23 import java.util.List;
24
25 import org.apache.openjpa.lib.util.Localizer.Message;
26 import org.apache.openjpa.util.LockException;
27 import org.apache.openjpa.util.ObjectExistsException;
28 import org.apache.openjpa.util.ObjectNotFoundException;
29 import org.apache.openjpa.util.OpenJPAException;
30 import org.apache.openjpa.util.OptimisticException;
31 import org.apache.openjpa.util.ReferentialIntegrityException;
32 import org.apache.openjpa.util.StoreException;
33
34 /**
35 * Helper class for converting a {@link SQLException} into
36 * the appropriate OpenJPA type.
37 *
38 * @author Marc Prud'hommeaux
39 * @nojavadoc
40 */
41 public class SQLExceptions {
42
43 private static final SQLException[] EMPTY_EXCEPS = new SQLException[0];
44
45 /**
46 * Convert the specified exception into a {@link StoreException}.
47 */
48 public static OpenJPAException getStore(SQLException se) {
49 return getStore(se, null, null);
50 }
51
52 /**
53 * Convert the specified exception into a {@link OpenJPAException}.
54 */
55 public static OpenJPAException getStore(SQLException se, Object failed) {
56 return getStore(se, failed, null);
57 }
58
59 /**
60 * Convert the specified exception into a {@link StoreException}.
61 */
62 public static OpenJPAException getStore(SQLException se,
63 DBDictionary dict) {
64 return getStore(se.getMessage(), se, dict);
65 }
66
67 /**
68 * Convert the specified exception into a {@link StoreException}.
69 */
70 public static OpenJPAException getStore(SQLException se, Object failed,
71 DBDictionary dict) {
72 return getStore(se.getMessage(), se, failed, dict);
73 }
74
75 /**
76 * Convert the specified exception into a {@link StoreException}.
77 */
78 public static OpenJPAException getStore(Message msg, SQLException se,
79 DBDictionary dict) {
80 return getStore(msg.getMessage(), se, null, dict);
81 }
82
83 /**
84 * Convert the specified exception into a {@link StoreException}.
85 */
86 public static OpenJPAException getStore(String msg, SQLException se,
87 DBDictionary dict) {
88 return getStore(msg, se, null, dict);
89 }
90
91 /**
92 * Convert the specified exception into a {@link StoreException}.
93 */
94 public static OpenJPAException getStore(String msg, SQLException se,
95 Object failed, DBDictionary dict) {
96 if (msg == null)
97 msg = se.getClass().getName();
98 SQLException[] ses = getSQLExceptions(se);
99 if (dict == null)
100 return new StoreException(msg).setFailedObject(failed).
101 setNestedThrowables(ses);
102 return dict.newStoreException(msg, ses, failed);
103 }
104
105 /**
106 * Returns an array of {@link SQLException} instances for the
107 * specified exception.
108 */
109 private static SQLException[] getSQLExceptions(SQLException se) {
110 if (se == null)
111 return EMPTY_EXCEPS;
112
113 List errs = new LinkedList();
114 while (se != null && !errs.contains(se)) {
115 errs.add(se);
116 se = se.getNextException();
117 }
118 return (SQLException[]) errs.toArray(new SQLException[errs.size()]);
119 }
120
121 /**
122 * Narrows the given SQLException to a specific type of
123 * {@link StoreException#getSubtype() StoreException} by analyzing the
124 * SQLState code supplied by SQLException. Each database-specific
125 * {@link DBDictionary dictionary} can supply a set of error codes that will
126 * map to a specific specific type of StoreException via
127 * {@link DBDictionary#getSQLStates(int) getSQLStates()} method.
128 * The default behavior is to return generic {@link StoreException
129 * StoreException}.
130 */
131 public static OpenJPAException narrow(String msg, SQLException se,
132 DBDictionary dict) {
133 String e = se.getSQLState();
134 if (dict.getSQLStates(StoreException.LOCK).contains(e))
135 return new LockException(msg);
136 else if (dict.getSQLStates(StoreException.OBJECT_EXISTS).contains(e))
137 return new ObjectExistsException(msg);
138 else if (dict.getSQLStates(StoreException.OBJECT_NOT_FOUND).contains(e))
139 return new ObjectNotFoundException(msg);
140 else if (dict.getSQLStates(StoreException.OPTIMISTIC).contains(e))
141 return new OptimisticException(msg);
142 else if (dict.getSQLStates(StoreException.REFERENTIAL_INTEGRITY)
143 .contains(e))
144 return new ReferentialIntegrityException(msg);
145 else
146 return new StoreException(msg);
147 }
148 }