001: /*
002: * Copyright 2003 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package velosurf.sql;
018:
019: import java.lang.reflect.Method;
020: import java.sql.*;
021: import java.util.Map;
022: import java.util.Properties;
023:
024: import velosurf.util.Logger;
025:
026: /** Connection wrapper class. Allows the handling of a busy state
027: *
028: * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
029: */
030:
031: public class ConnectionWrapper implements Connection {
032:
033: /**
034: * Constructor.
035: * @param driver infos on the driver
036: * @param connection connection to be wrapped
037: */
038: public ConnectionWrapper(DriverInfo driver, Connection connection) {
039: this .driver = driver;
040: this .connection = connection;
041: }
042:
043: /**
044: * Unwrap the connection.
045: * @return the unwrapped connection
046: */
047: public Connection unwrap() {
048: return connection;
049: }
050:
051: /**
052: * Create a statement.
053: * @return created statement
054: * @throws SQLException
055: */
056: public Statement createStatement() throws SQLException {
057: try {
058: enterBusyState();
059: return connection.createStatement();
060: } finally {
061: leaveBusyState();
062: }
063: }
064:
065: /**
066: * Prepare a statement.
067: * @param s SQL query
068: * @return prepared statement
069: * @throws SQLException
070: */
071: public synchronized PreparedStatement prepareStatement(String s)
072: throws SQLException {
073: try {
074: enterBusyState();
075: return connection.prepareStatement(s);
076: } finally {
077: leaveBusyState();
078: }
079: }
080:
081: /**
082: * Prepare a callable statement.
083: * @param s SQL query
084: * @return prepared callable statement
085: * @throws SQLException
086: */
087: public synchronized CallableStatement prepareCall(String s)
088: throws SQLException {
089: try {
090: enterBusyState();
091: return connection.prepareCall(s);
092: } finally {
093: leaveBusyState();
094: }
095: }
096:
097: /**
098: * Gets native SQL for a query.
099: * @param s query
100: * @return native SQL
101: * @throws SQLException
102: */
103: public synchronized String nativeSQL(String s) throws SQLException {
104: try {
105: enterBusyState();
106: return connection.nativeSQL(s);
107: } finally {
108: leaveBusyState();
109: }
110: }
111:
112: /**
113: * Set autocommit flag.
114: * @param flag autocommit
115: * @throws SQLException
116: */
117: public void setAutoCommit(boolean flag) throws SQLException {
118: connection.setAutoCommit(flag);
119: }
120:
121: /** Get autocommit flag.
122: *
123: * @return autocommit flag
124: * @throws SQLException
125: */
126: public boolean getAutoCommit() throws SQLException {
127: return connection.getAutoCommit();
128: }
129:
130: /** Commit.
131: *
132: * @throws SQLException
133: */
134: public synchronized void commit() throws SQLException {
135: try {
136: enterBusyState();
137: connection.commit();
138: } finally {
139: leaveBusyState();
140: }
141: }
142:
143: /** Rollback.
144: *
145: * @throws SQLException
146: */
147: public synchronized void rollback() throws SQLException {
148: try {
149: enterBusyState();
150: connection.rollback();
151: } finally {
152: leaveBusyState();
153: }
154: }
155:
156: /** Close.
157: *
158: * @throws SQLException
159: */
160: public void close() throws SQLException {
161: // since some sql drivers refuse to close a connection that has been interrupted,
162: // better handle this also ourselves
163: closed = true;
164: connection.close();
165: }
166:
167: /**
168: * Check the closed state.
169: * @return closed state
170: * @throws SQLException
171: */
172: public boolean isClosed() throws SQLException {
173: return (closed || connection.isClosed());
174: }
175:
176: /**
177: * Get meta data
178: * @return database meta data
179: * @throws SQLException
180: */
181: public DatabaseMetaData getMetaData() throws SQLException {
182: return connection.getMetaData();
183: }
184:
185: /**
186: * set read-only flag
187: * @param flag read-only
188: * @throws SQLException
189: */
190: public void setReadOnly(boolean flag) throws SQLException {
191: connection.setReadOnly(flag);
192: }
193:
194: /**
195: * Check the read-only state.
196: * @return read-only state
197: * @throws SQLException
198: */
199: public boolean isReadOnly() throws SQLException {
200: return connection.isReadOnly();
201: }
202:
203: /**
204: * Catalog setter.
205: * @param s catalog
206: * @throws SQLException
207: */
208: public void setCatalog(String s) throws SQLException {
209: connection.setCatalog(s);
210: }
211:
212: /**
213: * Catalog getter.
214: * @return catalog
215: * @throws SQLException
216: */
217: public String getCatalog() throws SQLException {
218: return connection.getCatalog();
219: }
220:
221: /**
222: * Transaction isolation setter.
223: * @param i transaction isolation
224: * @throws SQLException
225: */
226: public void setTransactionIsolation(int i) throws SQLException {
227: connection.setTransactionIsolation(i);
228: }
229:
230: /**
231: * Transaction isolation getter.
232: * @return transaction isolation
233: * @throws SQLException
234: */
235: public int getTransactionIsolation() throws SQLException {
236: return connection.getTransactionIsolation();
237: }
238:
239: /**
240: * Get SQL warnings.
241: * @return next SQL Warning.
242: * @throws SQLException
243: */
244: public SQLWarning getWarnings() throws SQLException {
245: return connection.getWarnings();
246: }
247:
248: /**
249: * Clear SQL warnings.
250: * @throws SQLException
251: */
252: public void clearWarnings() throws SQLException {
253: connection.clearWarnings();
254: }
255:
256: /** Create a statement.
257: *
258: * @param i result set type
259: * @param j result set concurrency
260: * @return new statement
261: * @throws SQLException
262: */
263: public synchronized Statement createStatement(int i, int j)
264: throws SQLException {
265: try {
266: enterBusyState();
267: return connection.createStatement(i, j);
268: } finally {
269: leaveBusyState();
270: }
271:
272: }
273:
274: /**
275: * Prepare a statement.
276: * @param s SQL query
277: * @param i result set type
278: * @param j result set concurrency
279: * @return prepared statement
280: * @throws SQLException
281: */
282: public synchronized PreparedStatement prepareStatement(String s,
283: int i, int j) throws SQLException {
284: try {
285: enterBusyState();
286: return connection.prepareStatement(s, i, j);
287: } finally {
288: leaveBusyState();
289: }
290: }
291:
292: /**
293: * Prepare a call.
294: * @param s SQL query
295: * @param i result set type
296: * @param j result set concurrency
297: * @return callable statement
298: * @throws SQLException
299: */
300: public synchronized CallableStatement prepareCall(String s, int i,
301: int j) throws SQLException {
302: try {
303: enterBusyState();
304: return connection.prepareCall(s, i, j);
305: } finally {
306: leaveBusyState();
307: }
308: }
309:
310: /**
311: * Get type map.
312: * @return type map
313: * @throws SQLException
314: */
315: public Map getTypeMap() throws SQLException {
316: return connection.getTypeMap();
317: }
318:
319: /**
320: * Set type map.
321: * @param map type map
322: * @throws SQLException
323: */
324: public void setTypeMap(Map map) throws SQLException {
325: connection.setTypeMap(map);
326: }
327:
328: /**
329: * Set holdability.
330: * @param i holdability
331: * @throws SQLException
332: */
333: public void setHoldability(int i) throws SQLException {
334: connection.setHoldability(i);
335: }
336:
337: /**
338: * Get holdability.
339: * @return holdability
340: * @throws SQLException
341: */
342: public int getHoldability() throws SQLException {
343: return connection.getHoldability();
344: }
345:
346: /**
347: * Savepoint setter.
348: * @return save point
349: * @throws SQLException
350: */
351: public synchronized Savepoint setSavepoint() throws SQLException {
352: return connection.setSavepoint();
353: }
354:
355: /**
356: * Set named savepoint.
357: * @param s savepoint name
358: * @return savepoint
359: * @throws SQLException
360: */
361: public synchronized Savepoint setSavepoint(String s)
362: throws SQLException {
363: return connection.setSavepoint(s);
364: }
365:
366: /**
367: * Rollback.
368: * @param savepoint savepoint
369: * @throws SQLException
370: */
371: public synchronized void rollback(Savepoint savepoint)
372: throws SQLException {
373: connection.rollback(savepoint);
374: }
375:
376: /** Release savepoint.
377: *
378: * @param savepoint savepoint
379: * @throws SQLException
380: */
381: public synchronized void releaseSavepoint(Savepoint savepoint)
382: throws SQLException {
383: connection.releaseSavepoint(savepoint);
384: }
385:
386: /**
387: * Create a statement.
388: * @param i result set type
389: * @param j result set concurrency
390: * @param k result set holdability
391: * @return created statement
392: * @throws SQLException
393: */
394: public synchronized Statement createStatement(int i, int j, int k)
395: throws SQLException {
396: try {
397: enterBusyState();
398: return connection.createStatement(i, j, k);
399: } finally {
400: leaveBusyState();
401: }
402: }
403:
404: /**
405: * Prepare a statement.
406: * @param s SQL query
407: * @param i result set type
408: * @param j result set concurrency
409: * @param k result set holdability
410: * @return prepared statement
411: * @throws SQLException
412: */
413: public synchronized PreparedStatement prepareStatement(String s,
414: int i, int j, int k) throws SQLException {
415: try {
416: enterBusyState();
417: return connection.prepareStatement(s, i, j, k);
418: } finally {
419: leaveBusyState();
420: }
421: }
422:
423: /**
424: * Prepare a callable statement.
425: * @param s SQL query
426: * @param i result set type
427: * @param j result set concurrency
428: * @param k result set holdability
429: * @return prepared statement
430: * @throws SQLException
431: */
432: public synchronized CallableStatement prepareCall(String s, int i,
433: int j, int k) throws SQLException {
434: try {
435: enterBusyState();
436: return connection.prepareCall(s, i, j, k);
437: } finally {
438: leaveBusyState();
439: }
440: }
441:
442: /**
443: * Prepare a statement.
444: * @param s SQL query
445: * @param i autogenerated keys
446: * @return prepared statement
447: * @throws SQLException
448: */
449: public synchronized PreparedStatement prepareStatement(String s,
450: int i) throws SQLException {
451: try {
452: enterBusyState();
453: return connection.prepareStatement(s, i);
454: } finally {
455: leaveBusyState();
456: }
457: }
458:
459: /**
460: * Prepare a statement.
461: * @param s SQL query
462: * @param ai autogenerated keys column indexes
463: * @return prepared statement
464: * @throws SQLException
465: */
466: public synchronized PreparedStatement prepareStatement(String s,
467: int ai[]) throws SQLException {
468: try {
469: enterBusyState();
470: return connection.prepareStatement(s, ai);
471: } finally {
472: leaveBusyState();
473: }
474: }
475:
476: /**
477: * Prepare a statement.
478: * @param s SQL query
479: * @param as autogenerated keys column names
480: * @return prepared statement
481: * @throws SQLException
482: */
483: public synchronized PreparedStatement prepareStatement(String s,
484: String as[]) throws SQLException {
485: try {
486: enterBusyState();
487: return connection.prepareStatement(s, as);
488: } finally {
489: leaveBusyState();
490: }
491: }
492:
493: /** Enter busy state.
494: */
495: public void enterBusyState() {
496: //Logger.trace("connection #"+toString()+": entering busy state.");
497: busy++;
498: }
499:
500: /** Leave busy state.
501: */
502: public void leaveBusyState() {
503: busy--;
504: //Logger.trace("connection #"+toString()+": leaving busy state.");
505: }
506:
507: /** Check busy state.
508: * @return busy state
509: */
510: public boolean isBusy() {
511: return busy > 0;
512: }
513:
514: /**
515: * Get last inserted ID.
516: * @param statement
517: * @return last inserted id
518: * @throws SQLException
519: */
520: public long getLastInsertId(Statement statement)
521: throws SQLException {
522: return driver.getLastInsertId(statement);
523: }
524:
525: /** Check connection.
526: *
527: * @return true if the connection is ok
528: */
529: public synchronized boolean check() {
530: try {
531: String checkQuery = driver.getPingQuery();
532: if (checkQuery == null) {
533: // at least, call isOpen
534: if (isClosed())
535: throw new Exception("Connection is closed");
536: } else {
537: if (checkStatement == null)
538: checkStatement = prepareStatement(checkQuery);
539: checkStatement.executeQuery();
540: }
541: return true;
542: } catch (Exception e) {
543: Logger.warn("Exception while checking connection!");
544: Logger.info("Refreshing...");
545: return false;
546: }
547: }
548:
549: /** Infos on the driver. */
550: private DriverInfo driver = null;
551: /** Wrapped connection. */
552: private Connection connection = null;
553: /** Busy state. */
554: private int busy = 0;
555: /** Closed state. */
556: private boolean closed = false;
557:
558: /** statement used to check connection ("select 1").
559: */
560: private PreparedStatement checkStatement = null;
561:
562: /*
563: * stores new 1.6 methods using reflection api to ensure backward compatibility
564: */
565:
566: static Method _createClob = null;
567: static Method _createBlob = null;
568: static Method _createNClob = null;
569: static Method _createSQLXML = null;
570: static Method _isValid = null;
571: static Method _setClientInfo = null;
572: static Method _setClientInfo2 = null;
573: static Method _getClientInfo = null;
574: static Method _getClientInfo2 = null;
575: static Method _createArrayOf = null;
576: static Method _createStruct = null;
577: static Method _isWrapperFor = null;
578:
579: static {
580: try {
581: _createClob = getConnectionMethod("createClob",
582: new Class[] {});
583: _createBlob = getConnectionMethod("createBlob",
584: new Class[] {});
585: _createNClob = getConnectionMethod("createNClob",
586: new Class[] {});
587: _createSQLXML = getConnectionMethod("createSQLXML",
588: new Class[] {});
589: _isValid = getConnectionMethod("isValid",
590: new Class[] { int.class });
591: _setClientInfo = getConnectionMethod("setClientInfo",
592: new Class[] { String.class, String.class });
593: _setClientInfo2 = getConnectionMethod("setClientInfo",
594: new Class[] { Properties.class });
595: _getClientInfo = getConnectionMethod("getClientInfo",
596: new Class[] {});
597: _getClientInfo2 = getConnectionMethod("getClientInfo",
598: new Class[] { String.class });
599: _createArrayOf = getConnectionMethod("createArrayOf",
600: new Class[] { String.class,
601: Class.forName("[Ljava.lang.Object;") });
602: _createStruct = getConnectionMethod("createStruct",
603: new Class[] { String.class,
604: Class.forName("[Ljava.lang.Object;") });
605: _isWrapperFor = getConnectionMethod("isWrapperFor",
606: new Class[] { Class.class });
607: } catch (Exception e) {
608: }
609: }
610:
611: static private Method getConnectionMethod(String name,
612: Class[] parameterTypes) {
613: try {
614: return Connection.class.getMethod(name, parameterTypes);
615: } catch (NoSuchMethodException nsme) {
616: return null;
617: }
618: }
619:
620: public Clob createClob() throws SQLException {
621: if (_createClob == null) {
622: throw new SQLException("Unsupported method.");
623: } else {
624: try {
625: return (Clob) _createClob.invoke(connection,
626: new Object[] {});
627: } catch (Exception e) {
628: Throwable cause = e.getCause();
629: if (cause == null) {
630: cause = e;
631: }
632: if (cause instanceof SQLException) {
633: throw (SQLException) cause;
634: } else {
635: throw new SQLException(cause);
636: }
637: }
638: }
639: }
640:
641: public Blob createBlob() throws SQLException {
642: if (_createBlob == null) {
643: throw new SQLException("Unsupported method.");
644: } else {
645: try {
646: return (Blob) _createBlob.invoke(connection,
647: new Object[] {});
648: } catch (Exception e) {
649: Throwable cause = e.getCause();
650: if (cause == null) {
651: cause = e;
652: }
653: if (cause instanceof SQLException) {
654: throw (SQLException) cause;
655: } else {
656: throw new SQLException(cause);
657: }
658: }
659: }
660: }
661:
662: public NClob createNClob() throws SQLException {
663: if (_createNClob == null) {
664: throw new SQLException("Unsupported method.");
665: } else {
666: try {
667: return (NClob) _createNClob.invoke(connection,
668: new Object[] {});
669: } catch (Exception e) {
670: Throwable cause = e.getCause();
671: if (cause == null) {
672: cause = e;
673: }
674: if (cause instanceof SQLException) {
675: throw (SQLException) cause;
676: } else {
677: throw new SQLException(cause);
678: }
679: }
680: }
681: }
682:
683: public SQLXML createSQLXML() throws SQLException {
684: if (_createSQLXML == null) {
685: throw new SQLException("Unsupported method.");
686: } else {
687: try {
688: return (SQLXML) _createSQLXML.invoke(connection,
689: new Object[] {});
690: } catch (Exception e) {
691: Throwable cause = e.getCause();
692: if (cause == null) {
693: cause = e;
694: }
695: if (cause instanceof SQLException) {
696: throw (SQLException) cause;
697: } else {
698: throw new SQLException(cause);
699: }
700: }
701: }
702: }
703:
704: public boolean isValid(int timeout) throws SQLException {
705: if (_isValid == null) {
706: throw new SQLException("Unsupported method.");
707: } else {
708: try {
709: return (Boolean) _isValid.invoke(connection,
710: new Object[] { timeout });
711: } catch (Exception e) {
712: Throwable cause = e.getCause();
713: if (cause == null) {
714: cause = e;
715: }
716: if (cause instanceof SQLException) {
717: throw (SQLException) cause;
718: } else {
719: throw new SQLException(cause);
720: }
721: }
722: }
723: }
724:
725: public void setClientInfo(String name, String value) {
726: if (_setClientInfo == null) {
727: throw new RuntimeException("Unsupported method.");
728: } else {
729: try {
730: _setClientInfo.invoke(connection, new Object[] { name,
731: value });
732: } catch (Exception e) {
733: throw new RuntimeException(e);
734: }
735: }
736: }
737:
738: public void setClientInfo(Properties properties) {
739: if (_setClientInfo2 == null) {
740: throw new RuntimeException("Unsupported method.");
741: } else {
742: try {
743: _setClientInfo2.invoke(connection,
744: new Object[] { properties });
745: } catch (Exception e) {
746: throw new RuntimeException(e);
747: }
748: }
749: }
750:
751: public Properties getClientInfo() throws SQLException {
752: if (_getClientInfo == null) {
753: throw new SQLException("Unsupported method.");
754: } else {
755: try {
756: return (Properties) _getClientInfo.invoke(connection,
757: new Object[] {});
758: } catch (Exception e) {
759: Throwable cause = e.getCause();
760: if (cause == null) {
761: cause = e;
762: }
763: if (cause instanceof SQLException) {
764: throw (SQLException) cause;
765: } else {
766: throw new SQLException(cause);
767: }
768: }
769: }
770: }
771:
772: public String getClientInfo(String name) throws SQLException {
773: if (_getClientInfo2 == null) {
774: throw new SQLException("Unsupported method.");
775: } else {
776: try {
777: return (String) _getClientInfo2.invoke(connection,
778: new Object[] { name });
779: } catch (Exception e) {
780: Throwable cause = e.getCause();
781: if (cause == null) {
782: cause = e;
783: }
784: if (cause instanceof SQLException) {
785: throw (SQLException) cause;
786: } else {
787: throw new SQLException(cause);
788: }
789: }
790: }
791: }
792:
793: public Array createArrayOf(String typeName, Object[] elements)
794: throws SQLException {
795: if (_createArrayOf == null) {
796: throw new SQLException("Unsupported method.");
797: } else {
798: try {
799: return (Array) _createArrayOf.invoke(connection,
800: new Object[] { typeName, elements });
801: } catch (Exception e) {
802: Throwable cause = e.getCause();
803: if (cause == null) {
804: cause = e;
805: }
806: if (cause instanceof SQLException) {
807: throw (SQLException) cause;
808: } else {
809: throw new SQLException(cause);
810: }
811: }
812: }
813: }
814:
815: public Struct createStruct(String typeName, Object[] attributes)
816: throws SQLException {
817: if (_createStruct == null) {
818: throw new SQLException("Unsupported method.");
819: } else {
820: try {
821: return (Struct) _createStruct.invoke(connection,
822: new Object[] { typeName, attributes });
823: } catch (Exception e) {
824: Throwable cause = e.getCause();
825: if (cause == null) {
826: cause = e;
827: }
828: if (cause instanceof SQLException) {
829: throw (SQLException) cause;
830: } else {
831: throw new SQLException(cause);
832: }
833: }
834: }
835: }
836:
837: public boolean isWrapperFor(Class<?> iface) throws SQLException {
838: throw new SQLException("Unsupported method.");
839: }
840:
841: public <T> T unwrap(Class<T> iface) throws SQLException {
842: throw new SQLException("Unsupported method.");
843: }
844:
845: }
|