001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.lib.jdbc;
020:
021: import java.lang.reflect.Method;
022: import java.sql.CallableStatement;
023: import java.sql.Connection;
024: import java.sql.DatabaseMetaData;
025: import java.sql.PreparedStatement;
026: import java.sql.ResultSet;
027: import java.sql.SQLException;
028: import java.sql.SQLWarning;
029: import java.sql.Savepoint;
030: import java.sql.Statement;
031: import java.util.HashMap;
032: import java.util.Map;
033:
034: import org.apache.commons.lang.exception.NestableRuntimeException;
035: import org.apache.openjpa.lib.util.Closeable;
036: import org.apache.openjpa.lib.util.Localizer;
037: import serp.util.Numbers;
038:
039: /**
040: * Wrapper around an existing connection. Subclasses can override the
041: * methods whose behavior they mean to change. The <code>equals</code> and
042: * <code>hashCode</code> methods pass through to the base underlying data
043: * store connection.
044: *
045: * @author Abe White
046: */
047: public class DelegatingConnection implements Connection, Closeable {
048:
049: // jdbc 3 method keys
050: private static final Object SET_HOLDABILITY = new Object();
051: private static final Object GET_HOLDABILITY = new Object();
052: private static final Object SET_SAVEPOINT_NONAME = new Object();
053: private static final Object SET_SAVEPOINT = new Object();
054: private static final Object ROLLBACK_SAVEPOINT = new Object();
055: private static final Object RELEASE_SAVEPOINT = new Object();
056: private static final Object CREATE_STATEMENT = new Object();
057: private static final Object PREPARE_STATEMENT = new Object();
058: private static final Object PREPARE_CALL = new Object();
059: private static final Object PREPARE_WITH_KEYS = new Object();
060: private static final Object PREPARE_WITH_INDEX = new Object();
061: private static final Object PREPARE_WITH_NAMES = new Object();
062:
063: private static final Localizer _loc = Localizer
064: .forPackage(DelegatingConnection.class);
065:
066: private static final Map _jdbc3;
067:
068: static {
069: boolean jdbc3 = false;
070: Method m = null;
071: try {
072: m = Connection.class.getMethod("setSavepoint",
073: new Class[] { String.class });
074: jdbc3 = true;
075: } catch (Throwable t) {
076: }
077:
078: if (jdbc3) {
079: _jdbc3 = new HashMap();
080: _jdbc3.put(SET_SAVEPOINT, m);
081: } else
082: _jdbc3 = null;
083: }
084:
085: private final Connection _conn;
086: private final DelegatingConnection _del;
087:
088: public DelegatingConnection(Connection conn) {
089: _conn = conn;
090: if (conn instanceof DelegatingConnection)
091: _del = (DelegatingConnection) _conn;
092: else
093: _del = null;
094: }
095:
096: /**
097: * Return the wrapped connection.
098: */
099: public Connection getDelegate() {
100: return _conn;
101: }
102:
103: /**
104: * Return the base underlying data store connection.
105: */
106: public Connection getInnermostDelegate() {
107: return (_del == null) ? _conn : _del.getInnermostDelegate();
108: }
109:
110: public int hashCode() {
111: return getInnermostDelegate().hashCode();
112: }
113:
114: public boolean equals(Object other) {
115: if (other == this )
116: return true;
117: if (other instanceof DelegatingConnection)
118: other = ((DelegatingConnection) other)
119: .getInnermostDelegate();
120: return getInnermostDelegate().equals(other);
121: }
122:
123: public String toString() {
124: StringBuffer buf = new StringBuffer("conn ").append(hashCode());
125: appendInfo(buf);
126: return buf.toString();
127: }
128:
129: protected void appendInfo(StringBuffer buf) {
130: if (_del != null)
131: _del.appendInfo(buf);
132: }
133:
134: public Statement createStatement() throws SQLException {
135: return createStatement(true);
136: }
137:
138: /**
139: * Create a statement, with the option of not wrapping it in a
140: * {@link DelegatingStatement}, which is the default.
141: */
142: protected Statement createStatement(boolean wrap)
143: throws SQLException {
144: Statement stmnt;
145: if (_del != null)
146: stmnt = _del.createStatement(false);
147: else
148: stmnt = _conn.createStatement();
149: if (wrap)
150: stmnt = new DelegatingStatement(stmnt, this );
151: return stmnt;
152: }
153:
154: public PreparedStatement prepareStatement(String str)
155: throws SQLException {
156: return prepareStatement(str, true);
157: }
158:
159: /**
160: * Prepare a statement, with the option of not wrapping it in a
161: * {@link DelegatingPreparedStatement}, which is the default.
162: */
163: protected PreparedStatement prepareStatement(String str,
164: boolean wrap) throws SQLException {
165: PreparedStatement stmnt;
166: if (_del != null)
167: stmnt = _del.prepareStatement(str, false);
168: else
169: stmnt = _conn.prepareStatement(str,
170: ResultSet.TYPE_FORWARD_ONLY,
171: ResultSet.CONCUR_READ_ONLY);
172: if (wrap)
173: stmnt = new DelegatingPreparedStatement(stmnt, this );
174: return stmnt;
175: }
176:
177: public CallableStatement prepareCall(String str)
178: throws SQLException {
179: return prepareCall(str, true);
180: }
181:
182: /**
183: * Prepare a call, with the option of not wrapping it in a
184: * {@link DelegatingCallableStatement}, which is the default.
185: */
186: protected CallableStatement prepareCall(String str, boolean wrap)
187: throws SQLException {
188: CallableStatement stmnt;
189: if (_del != null)
190: stmnt = _del.prepareCall(str, false);
191: else
192: stmnt = _conn.prepareCall(str);
193: if (wrap)
194: stmnt = new DelegatingCallableStatement(stmnt, this );
195: return stmnt;
196: }
197:
198: public String nativeSQL(String str) throws SQLException {
199: return _conn.nativeSQL(str);
200: }
201:
202: public void setAutoCommit(boolean bool) throws SQLException {
203: _conn.setAutoCommit(bool);
204: }
205:
206: public boolean getAutoCommit() throws SQLException {
207: return _conn.getAutoCommit();
208: }
209:
210: public void commit() throws SQLException {
211: _conn.commit();
212: }
213:
214: public void rollback() throws SQLException {
215: _conn.rollback();
216: }
217:
218: public void close() throws SQLException {
219: _conn.close();
220: }
221:
222: public boolean isClosed() throws SQLException {
223: return _conn.isClosed();
224: }
225:
226: public DatabaseMetaData getMetaData() throws SQLException {
227: return getMetaData(true);
228: }
229:
230: /**
231: * Return the metadata, with the option of not wrapping it in a
232: * {@link DelegatingDatabaseMetaData}, which is the default.
233: */
234: protected DatabaseMetaData getMetaData(boolean wrap)
235: throws SQLException {
236: DatabaseMetaData meta;
237: if (_del != null)
238: meta = _del.getMetaData(false);
239: else
240: meta = _conn.getMetaData();
241: if (wrap)
242: meta = new DelegatingDatabaseMetaData(meta, this );
243: return meta;
244: }
245:
246: public void setReadOnly(boolean bool) throws SQLException {
247: _conn.setReadOnly(bool);
248: }
249:
250: public boolean isReadOnly() throws SQLException {
251: return _conn.isReadOnly();
252: }
253:
254: public void setCatalog(String str) throws SQLException {
255: _conn.setCatalog(str);
256: }
257:
258: public String getCatalog() throws SQLException {
259: return _conn.getCatalog();
260: }
261:
262: public void setTransactionIsolation(int i) throws SQLException {
263: _conn.setTransactionIsolation(i);
264: }
265:
266: public int getTransactionIsolation() throws SQLException {
267: return _conn.getTransactionIsolation();
268: }
269:
270: public SQLWarning getWarnings() throws SQLException {
271: return _conn.getWarnings();
272: }
273:
274: public void clearWarnings() throws SQLException {
275: _conn.clearWarnings();
276: }
277:
278: public Statement createStatement(int type, int concur)
279: throws SQLException {
280: return createStatement(type, concur, true);
281: }
282:
283: /**
284: * Create a statement, with the option of not wrapping it in a
285: * {@link DelegatingStatement}, which is the default.
286: */
287: protected Statement createStatement(int type, int concur,
288: boolean wrap) throws SQLException {
289: Statement stmnt;
290: if (_del != null)
291: stmnt = _del.createStatement(type, concur, false);
292: else
293: stmnt = _conn.createStatement(type, concur);
294: if (wrap)
295: stmnt = new DelegatingStatement(stmnt, this );
296: return stmnt;
297: }
298:
299: public PreparedStatement prepareStatement(String str, int type,
300: int concur) throws SQLException {
301: return prepareStatement(str, type, concur, true);
302: }
303:
304: /**
305: * Prepare a statement, with the option of not wrapping it in a
306: * {@link DelegatingPreparedStatement}, which is the default.
307: */
308: protected PreparedStatement prepareStatement(String str, int type,
309: int concur, boolean wrap) throws SQLException {
310: PreparedStatement stmnt;
311: if (_del != null)
312: stmnt = _del.prepareStatement(str, type, concur, false);
313: else
314: stmnt = _conn.prepareStatement(str, type, concur);
315: if (wrap)
316: stmnt = new DelegatingPreparedStatement(stmnt, this );
317: return stmnt;
318: }
319:
320: public CallableStatement prepareCall(String str, int type,
321: int concur) throws SQLException {
322: return prepareCall(str, type, concur, true);
323: }
324:
325: /**
326: * Prepare a call, with the option of not wrapping it in a
327: * {@link DelegatingCallableStatement}, which is the default.
328: */
329: protected CallableStatement prepareCall(String str, int type,
330: int concur, boolean wrap) throws SQLException {
331: CallableStatement stmnt;
332: if (_del != null)
333: stmnt = _del.prepareCall(str, type, concur, false);
334: else
335: stmnt = _conn.prepareCall(str, type, concur);
336: if (wrap)
337: stmnt = new DelegatingCallableStatement(stmnt, this );
338: return stmnt;
339: }
340:
341: public Map getTypeMap() throws SQLException {
342: return _conn.getTypeMap();
343: }
344:
345: public void setTypeMap(Map map) throws SQLException {
346: _conn.setTypeMap(map);
347: }
348:
349: // JDBC 3.0 methods follow; these are required to be able to
350: // compile against JDK 1.4; these methods will not work on
351: // previous JVMs
352:
353: public void setHoldability(int holdability) throws SQLException {
354: assertJDBC3();
355: Method m = (Method) _jdbc3.get(SET_HOLDABILITY);
356: if (m == null)
357: m = createJDBC3Method(SET_HOLDABILITY, "setHoldability",
358: new Class[] { int.class });
359: invokeJDBC3(m, new Object[] { Numbers.valueOf(holdability) });
360: }
361:
362: public int getHoldability() throws SQLException {
363: assertJDBC3();
364: Method m = (Method) _jdbc3.get(GET_HOLDABILITY);
365: if (m == null)
366: m = createJDBC3Method(GET_HOLDABILITY, "getHoldability",
367: null);
368: return ((Number) invokeJDBC3(m, null)).intValue();
369: }
370:
371: public Savepoint setSavepoint() throws SQLException {
372: assertJDBC3();
373: Method m = (Method) _jdbc3.get(SET_SAVEPOINT_NONAME);
374: if (m == null)
375: m = createJDBC3Method(SET_SAVEPOINT_NONAME, "setSavepoint",
376: null);
377: return (Savepoint) invokeJDBC3(m, null);
378: }
379:
380: public Savepoint setSavepoint(String savepoint) throws SQLException {
381: assertJDBC3();
382: Method m = (Method) _jdbc3.get(SET_SAVEPOINT);
383: if (m == null)
384: m = createJDBC3Method(SET_SAVEPOINT, "setSavepoint",
385: new Class[] { String.class });
386: return (Savepoint) invokeJDBC3(m, new Object[] { savepoint });
387: }
388:
389: public void rollback(Savepoint savepoint) throws SQLException {
390: assertJDBC3();
391: Method m = (Method) _jdbc3.get(ROLLBACK_SAVEPOINT);
392: if (m == null)
393: m = createJDBC3Method(ROLLBACK_SAVEPOINT, "rollback",
394: new Class[] { Savepoint.class });
395: invokeJDBC3(m, new Object[] { savepoint });
396: }
397:
398: public void releaseSavepoint(Savepoint savepoint)
399: throws SQLException {
400: assertJDBC3();
401: Method m = (Method) _jdbc3.get(RELEASE_SAVEPOINT);
402: if (m == null)
403: m = createJDBC3Method(RELEASE_SAVEPOINT,
404: "releaseSavepoint", new Class[] { Savepoint.class });
405: invokeJDBC3(m, new Object[] { savepoint });
406: }
407:
408: public Statement createStatement(int resultSetType,
409: int resultSetConcurrency, int resultSetHoldability)
410: throws SQLException {
411: assertJDBC3();
412: return createStatement(resultSetType, resultSetConcurrency,
413: resultSetHoldability, true);
414: }
415:
416: protected Statement createStatement(int resultSetType,
417: int resultSetConcurrency, int resultSetHoldability,
418: boolean wrap) throws SQLException {
419: Statement stmnt;
420: if (_del != null)
421: stmnt = _del.createStatement(resultSetType,
422: resultSetConcurrency, resultSetHoldability, false);
423: else {
424: Method m = (Method) _jdbc3.get(CREATE_STATEMENT);
425: if (m == null)
426: m = createJDBC3Method(CREATE_STATEMENT,
427: "createStatement", new Class[] { int.class,
428: int.class, int.class });
429: stmnt = (Statement) invokeJDBC3(m, new Object[] {
430: Numbers.valueOf(resultSetType),
431: Numbers.valueOf(resultSetConcurrency),
432: Numbers.valueOf(resultSetHoldability) });
433: }
434: if (wrap)
435: stmnt = new DelegatingStatement(stmnt, this );
436: return stmnt;
437: }
438:
439: public PreparedStatement prepareStatement(String sql,
440: int resultSetType, int resultSetConcurrency,
441: int resultSetHoldability) throws SQLException {
442: assertJDBC3();
443: return prepareStatement(sql, resultSetType,
444: resultSetConcurrency, resultSetHoldability, true);
445: }
446:
447: protected PreparedStatement prepareStatement(String sql,
448: int resultSetType, int resultSetConcurrency,
449: int resultSetHoldability, boolean wrap) throws SQLException {
450: PreparedStatement stmnt;
451: if (_del != null)
452: stmnt = _del.prepareStatement(sql, resultSetType,
453: resultSetConcurrency, resultSetHoldability, false);
454: else {
455: Method m = (Method) _jdbc3.get(PREPARE_STATEMENT);
456: if (m == null)
457: m = createJDBC3Method(PREPARE_STATEMENT,
458: "prepareStatement", new Class[] { String.class,
459: int.class, int.class, int.class });
460: stmnt = (PreparedStatement) invokeJDBC3(m, new Object[] {
461: sql, Numbers.valueOf(resultSetType),
462: Numbers.valueOf(resultSetConcurrency),
463: Numbers.valueOf(resultSetHoldability) });
464: }
465: if (wrap)
466: stmnt = new DelegatingPreparedStatement(stmnt, this );
467: return stmnt;
468: }
469:
470: public CallableStatement prepareCall(String sql, int resultSetType,
471: int resultSetConcurrency, int resultSetHoldability)
472: throws SQLException {
473: assertJDBC3();
474: return prepareCall(sql, resultSetType, resultSetConcurrency,
475: resultSetHoldability, true);
476: }
477:
478: protected CallableStatement prepareCall(String sql,
479: int resultSetType, int resultSetConcurrency,
480: int resultSetHoldability, boolean wrap) throws SQLException {
481: CallableStatement stmnt;
482: if (_del != null)
483: stmnt = _del.prepareCall(sql, resultSetType,
484: resultSetConcurrency, resultSetHoldability, false);
485: else {
486: Method m = (Method) _jdbc3.get(PREPARE_CALL);
487: if (m == null)
488: m = createJDBC3Method(PREPARE_CALL, "prepareCall",
489: new Class[] { String.class, int.class,
490: int.class, int.class });
491: stmnt = (CallableStatement) invokeJDBC3(m, new Object[] {
492: sql, Numbers.valueOf(resultSetType),
493: Numbers.valueOf(resultSetConcurrency),
494: Numbers.valueOf(resultSetHoldability) });
495: }
496: if (wrap)
497: stmnt = new DelegatingCallableStatement(stmnt, this );
498: return stmnt;
499: }
500:
501: public PreparedStatement prepareStatement(String sql,
502: int autoGeneratedKeys) throws SQLException {
503: assertJDBC3();
504: return prepareStatement(sql, autoGeneratedKeys, true);
505: }
506:
507: protected PreparedStatement prepareStatement(String sql,
508: int autoGeneratedKeys, boolean wrap) throws SQLException {
509: PreparedStatement stmnt;
510: if (_del != null)
511: stmnt = _del.prepareStatement(sql, autoGeneratedKeys);
512: else {
513: Method m = (Method) _jdbc3.get(PREPARE_WITH_KEYS);
514: if (m == null)
515: m = createJDBC3Method(PREPARE_WITH_KEYS,
516: "prepareStatement", new Class[] { String.class,
517: int.class });
518: stmnt = (PreparedStatement) invokeJDBC3(m, new Object[] {
519: sql, Numbers.valueOf(autoGeneratedKeys) });
520: }
521: if (wrap)
522: stmnt = new DelegatingPreparedStatement(stmnt, this );
523: return stmnt;
524: }
525:
526: public PreparedStatement prepareStatement(String sql,
527: int[] columnIndexes) throws SQLException {
528: assertJDBC3();
529: return prepareStatement(sql, columnIndexes, true);
530: }
531:
532: protected PreparedStatement prepareStatement(String sql,
533: int[] columnIndexes, boolean wrap) throws SQLException {
534: PreparedStatement stmnt;
535: if (_del != null)
536: stmnt = _del.prepareStatement(sql, columnIndexes, wrap);
537: else {
538: Method m = (Method) _jdbc3.get(PREPARE_WITH_INDEX);
539: if (m == null)
540: m = createJDBC3Method(PREPARE_WITH_INDEX,
541: "prepareStatement", new Class[] { String.class,
542: int[].class });
543: stmnt = (PreparedStatement) invokeJDBC3(m, new Object[] {
544: sql, columnIndexes });
545: }
546: if (wrap)
547: stmnt = new DelegatingPreparedStatement(stmnt, this );
548: return stmnt;
549: }
550:
551: public PreparedStatement prepareStatement(String sql,
552: String[] columnNames) throws SQLException {
553: assertJDBC3();
554: return prepareStatement(sql, columnNames, true);
555: }
556:
557: protected PreparedStatement prepareStatement(String sql,
558: String[] columnNames, boolean wrap) throws SQLException {
559: assertJDBC3();
560: PreparedStatement stmnt;
561: if (_del != null)
562: stmnt = _del.prepareStatement(sql, columnNames, wrap);
563: else {
564: Method m = (Method) _jdbc3.get(PREPARE_WITH_NAMES);
565: if (m == null)
566: m = createJDBC3Method(PREPARE_WITH_NAMES,
567: "prepareStatement", new Class[] { String.class,
568: String[].class });
569: stmnt = (PreparedStatement) invokeJDBC3(m, new Object[] {
570: sql, columnNames });
571: }
572: if (wrap)
573: stmnt = new DelegatingPreparedStatement(stmnt, this );
574: return stmnt;
575: }
576:
577: private static void assertJDBC3() {
578: if (_jdbc3 == null)
579: throw new UnsupportedOperationException(_loc.get(
580: "not-jdbc3").getMessage());
581: }
582:
583: private Object invokeJDBC3(Method m, Object[] args)
584: throws SQLException {
585: try {
586: return m.invoke(_conn, args);
587: } catch (Throwable t) {
588: if (t instanceof SQLException)
589: throw (SQLException) t;
590: throw new NestableRuntimeException(_loc.get("invoke-jdbc3")
591: .getMessage(), t);
592: }
593: }
594:
595: private static Method createJDBC3Method(Object key, String name,
596: Class[] args) {
597: try {
598: Method m = Connection.class.getMethod(name, args);
599: _jdbc3.put(key, m);
600: return m;
601: } catch (Throwable t) {
602: throw new NestableRuntimeException(_loc.get("error-jdbc3")
603: .getMessage(), t);
604: }
605: }
606: }
|