1
17
18 package org.apache.tomcat.dbcp.dbcp2;
19
20 import java.sql.Array;
21 import java.sql.Blob;
22 import java.sql.CallableStatement;
23 import java.sql.ClientInfoStatus;
24 import java.sql.Clob;
25 import java.sql.Connection;
26 import java.sql.DatabaseMetaData;
27 import java.sql.NClob;
28 import java.sql.PreparedStatement;
29 import java.sql.ResultSet;
30 import java.sql.SQLClientInfoException;
31 import java.sql.SQLException;
32 import java.sql.SQLWarning;
33 import java.sql.SQLXML;
34 import java.sql.Savepoint;
35 import java.sql.Statement;
36 import java.sql.Struct;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Properties;
43 import java.util.concurrent.Executor;
44
45
62 public class DelegatingConnection<C extends Connection> extends AbandonedTrace implements Connection {
63
64 private static final Map<String, ClientInfoStatus> EMPTY_FAILED_PROPERTIES = Collections
65 .<String, ClientInfoStatus>emptyMap();
66
67
68 private volatile C connection;
69
70 private volatile boolean closed;
71
72 private boolean cacheState = true;
73 private Boolean autoCommitCached;
74 private Boolean readOnlyCached;
75 private Integer defaultQueryTimeoutSeconds;
76
77
83 public DelegatingConnection(final C c) {
84 super();
85 connection = c;
86 }
87
88
91 @SuppressWarnings("resource")
92 @Override
93 public synchronized String toString() {
94 String str = null;
95
96 final Connection conn = this.getInnermostDelegateInternal();
97 if (conn != null) {
98 try {
99 if (conn.isClosed()) {
100 str = "connection is closed";
101 } else {
102 final StringBuffer sb = new StringBuffer();
103 sb.append(hashCode());
104 final DatabaseMetaData meta = conn.getMetaData();
105 if (meta != null) {
106 sb.append(", URL=");
107 sb.append(meta.getURL());
108 sb.append(", UserName=");
109 sb.append(meta.getUserName());
110 sb.append(", ");
111 sb.append(meta.getDriverName());
112 str = sb.toString();
113 }
114 }
115 } catch (final SQLException ex) {
116
117 }
118 }
119 return str != null ? str : super.toString();
120 }
121
122
127 public C getDelegate() {
128 return getDelegateInternal();
129 }
130
131 protected final C getDelegateInternal() {
132 return connection;
133 }
134
135
142 @SuppressWarnings("resource")
143 public boolean innermostDelegateEquals(final Connection c) {
144 final Connection innerCon = getInnermostDelegateInternal();
145 if (innerCon == null) {
146 return c == null;
147 }
148 return innerCon.equals(c);
149 }
150
151
165 public Connection getInnermostDelegate() {
166 return getInnermostDelegateInternal();
167 }
168
169
175 @SuppressWarnings("resource")
176 public final Connection getInnermostDelegateInternal() {
177 Connection conn = connection;
178 while (conn != null && conn instanceof DelegatingConnection) {
179 conn = ((DelegatingConnection<?>) conn).getDelegateInternal();
180 if (this == conn) {
181 return null;
182 }
183 }
184 return conn;
185 }
186
187
193 public void setDelegate(final C connection) {
194 this.connection = connection;
195 }
196
197
206 @Override
207 public void close() throws SQLException {
208 if (!closed) {
209 closeInternal();
210 }
211 }
212
213 protected boolean isClosedInternal() {
214 return closed;
215 }
216
217 protected void setClosedInternal(final boolean closed) {
218 this.closed = closed;
219 }
220
221 protected final void closeInternal() throws SQLException {
222 try {
223 passivate();
224 } finally {
225 if (connection != null) {
226 boolean connectionIsClosed;
227 try {
228 connectionIsClosed = connection.isClosed();
229 } catch (final SQLException e) {
230
231 connectionIsClosed = false;
232 }
233 try {
234
235
236
237 if (!connectionIsClosed) {
238 connection.close();
239 }
240 } finally {
241 closed = true;
242 }
243 } else {
244 closed = true;
245 }
246 }
247 }
248
249 protected void handleException(final SQLException e) throws SQLException {
250 throw e;
251 }
252
253
261 protected <T extends Throwable> T handleExceptionNoThrow(final T e) {
262 return e;
263 }
264
265 private void initializeStatement(final DelegatingStatement ds) throws SQLException {
266 if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) {
267 ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue());
268 }
269 }
270
271 @Override
272 public Statement createStatement() throws SQLException {
273 checkOpen();
274 try {
275 final DelegatingStatement ds = new DelegatingStatement(this, connection.createStatement());
276 initializeStatement(ds);
277 return ds;
278 } catch (final SQLException e) {
279 handleException(e);
280 return null;
281 }
282 }
283
284 @Override
285 public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
286 checkOpen();
287 try {
288 final DelegatingStatement ds = new DelegatingStatement(this,
289 connection.createStatement(resultSetType, resultSetConcurrency));
290 initializeStatement(ds);
291 return ds;
292 } catch (final SQLException e) {
293 handleException(e);
294 return null;
295 }
296 }
297
298 @Override
299 public PreparedStatement prepareStatement(final String sql) throws SQLException {
300 checkOpen();
301 try {
302 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
303 connection.prepareStatement(sql));
304 initializeStatement(dps);
305 return dps;
306 } catch (final SQLException e) {
307 handleException(e);
308 return null;
309 }
310 }
311
312 @Override
313 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
314 throws SQLException {
315 checkOpen();
316 try {
317 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
318 connection.prepareStatement(sql, resultSetType, resultSetConcurrency));
319 initializeStatement(dps);
320 return dps;
321 } catch (final SQLException e) {
322 handleException(e);
323 return null;
324 }
325 }
326
327 @Override
328 public CallableStatement prepareCall(final String sql) throws SQLException {
329 checkOpen();
330 try {
331 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, connection.prepareCall(sql));
332 initializeStatement(dcs);
333 return dcs;
334 } catch (final SQLException e) {
335 handleException(e);
336 return null;
337 }
338 }
339
340 @Override
341 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
342 throws SQLException {
343 checkOpen();
344 try {
345 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this,
346 connection.prepareCall(sql, resultSetType, resultSetConcurrency));
347 initializeStatement(dcs);
348 return dcs;
349 } catch (final SQLException e) {
350 handleException(e);
351 return null;
352 }
353 }
354
355 @Override
356 public void clearWarnings() throws SQLException {
357 checkOpen();
358 try {
359 connection.clearWarnings();
360 } catch (final SQLException e) {
361 handleException(e);
362 }
363 }
364
365 @Override
366 public void commit() throws SQLException {
367 checkOpen();
368 try {
369 connection.commit();
370 } catch (final SQLException e) {
371 handleException(e);
372 }
373 }
374
375
380 public boolean getCacheState() {
381 return cacheState;
382 }
383
384 @Override
385 public boolean getAutoCommit() throws SQLException {
386 checkOpen();
387 if (cacheState && autoCommitCached != null) {
388 return autoCommitCached.booleanValue();
389 }
390 try {
391 autoCommitCached = Boolean.valueOf(connection.getAutoCommit());
392 return autoCommitCached.booleanValue();
393 } catch (final SQLException e) {
394 handleException(e);
395 return false;
396 }
397 }
398
399 @Override
400 public String getCatalog() throws SQLException {
401 checkOpen();
402 try {
403 return connection.getCatalog();
404 } catch (final SQLException e) {
405 handleException(e);
406 return null;
407 }
408 }
409
410 @Override
411 public DatabaseMetaData getMetaData() throws SQLException {
412 checkOpen();
413 try {
414 return new DelegatingDatabaseMetaData(this, connection.getMetaData());
415 } catch (final SQLException e) {
416 handleException(e);
417 return null;
418 }
419 }
420
421 @Override
422 public int getTransactionIsolation() throws SQLException {
423 checkOpen();
424 try {
425 return connection.getTransactionIsolation();
426 } catch (final SQLException e) {
427 handleException(e);
428 return -1;
429 }
430 }
431
432 @Override
433 public Map<String, Class<?>> getTypeMap() throws SQLException {
434 checkOpen();
435 try {
436 return connection.getTypeMap();
437 } catch (final SQLException e) {
438 handleException(e);
439 return null;
440 }
441 }
442
443 @Override
444 public SQLWarning getWarnings() throws SQLException {
445 checkOpen();
446 try {
447 return connection.getWarnings();
448 } catch (final SQLException e) {
449 handleException(e);
450 return null;
451 }
452 }
453
454 @Override
455 public boolean isReadOnly() throws SQLException {
456 checkOpen();
457 if (cacheState && readOnlyCached != null) {
458 return readOnlyCached.booleanValue();
459 }
460 try {
461 readOnlyCached = Boolean.valueOf(connection.isReadOnly());
462 return readOnlyCached.booleanValue();
463 } catch (final SQLException e) {
464 handleException(e);
465 return false;
466 }
467 }
468
469 @Override
470 public String nativeSQL(final String sql) throws SQLException {
471 checkOpen();
472 try {
473 return connection.nativeSQL(sql);
474 } catch (final SQLException e) {
475 handleException(e);
476 return null;
477 }
478 }
479
480 @Override
481 public void rollback() throws SQLException {
482 checkOpen();
483 try {
484 connection.rollback();
485 } catch (final SQLException e) {
486 handleException(e);
487 }
488 }
489
490
496 public Integer getDefaultQueryTimeout() {
497 return defaultQueryTimeoutSeconds;
498 }
499
500
507 public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) {
508 this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds;
509 }
510
511
517 public void setCacheState(final boolean cacheState) {
518 this.cacheState = cacheState;
519 }
520
521
525 public void clearCachedState() {
526 autoCommitCached = null;
527 readOnlyCached = null;
528 if (connection instanceof DelegatingConnection) {
529 ((DelegatingConnection<?>) connection).clearCachedState();
530 }
531 }
532
533 @Override
534 public void setAutoCommit(final boolean autoCommit) throws SQLException {
535 checkOpen();
536 try {
537 connection.setAutoCommit(autoCommit);
538 if (cacheState) {
539 autoCommitCached = Boolean.valueOf(autoCommit);
540 }
541 } catch (final SQLException e) {
542 autoCommitCached = null;
543 handleException(e);
544 }
545 }
546
547 @Override
548 public void setCatalog(final String catalog) throws SQLException {
549 checkOpen();
550 try {
551 connection.setCatalog(catalog);
552 } catch (final SQLException e) {
553 handleException(e);
554 }
555 }
556
557 @Override
558 public void setReadOnly(final boolean readOnly) throws SQLException {
559 checkOpen();
560 try {
561 connection.setReadOnly(readOnly);
562 if (cacheState) {
563 readOnlyCached = Boolean.valueOf(readOnly);
564 }
565 } catch (final SQLException e) {
566 readOnlyCached = null;
567 handleException(e);
568 }
569 }
570
571 @Override
572 public void setTransactionIsolation(final int level) throws SQLException {
573 checkOpen();
574 try {
575 connection.setTransactionIsolation(level);
576 } catch (final SQLException e) {
577 handleException(e);
578 }
579 }
580
581 @Override
582 public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
583 checkOpen();
584 try {
585 connection.setTypeMap(map);
586 } catch (final SQLException e) {
587 handleException(e);
588 }
589 }
590
591 @Override
592 public boolean isClosed() throws SQLException {
593 return closed || connection == null || connection.isClosed();
594 }
595
596 protected void checkOpen() throws SQLException {
597 if (closed) {
598 if (null != connection) {
599 String label = "";
600 try {
601 label = connection.toString();
602 } catch (final Exception ex) {
603
604 }
605 throw new SQLException("Connection " + label + " is closed.");
606 }
607 throw new SQLException("Connection is null.");
608 }
609 }
610
611 protected void activate() {
612 closed = false;
613 setLastUsed();
614 if (connection instanceof DelegatingConnection) {
615 ((DelegatingConnection<?>) connection).activate();
616 }
617 }
618
619 protected void passivate() throws SQLException {
620
621
622
623 final List<AbandonedTrace> traces = getTrace();
624 if (traces != null && !traces.isEmpty()) {
625 final List<Exception> thrownList = new ArrayList<>();
626 final Iterator<AbandonedTrace> traceIter = traces.iterator();
627 while (traceIter.hasNext()) {
628 final Object trace = traceIter.next();
629 if (trace instanceof Statement) {
630 try {
631 ((Statement) trace).close();
632 } catch (Exception e) {
633 thrownList.add(e);
634 }
635 } else if (trace instanceof ResultSet) {
636
637
638 try {
639 ((ResultSet) trace).close();
640 } catch (Exception e) {
641 thrownList.add(e);
642 }
643 }
644 }
645 clearTrace();
646 if (!thrownList.isEmpty()) {
647 throw new SQLExceptionList(thrownList);
648 }
649 }
650 setLastUsed(0);
651 }
652
653 @Override
654 public int getHoldability() throws SQLException {
655 checkOpen();
656 try {
657 return connection.getHoldability();
658 } catch (final SQLException e) {
659 handleException(e);
660 return 0;
661 }
662 }
663
664 @Override
665 public void setHoldability(final int holdability) throws SQLException {
666 checkOpen();
667 try {
668 connection.setHoldability(holdability);
669 } catch (final SQLException e) {
670 handleException(e);
671 }
672 }
673
674 @Override
675 public Savepoint setSavepoint() throws SQLException {
676 checkOpen();
677 try {
678 return connection.setSavepoint();
679 } catch (final SQLException e) {
680 handleException(e);
681 return null;
682 }
683 }
684
685 @Override
686 public Savepoint setSavepoint(final String name) throws SQLException {
687 checkOpen();
688 try {
689 return connection.setSavepoint(name);
690 } catch (final SQLException e) {
691 handleException(e);
692 return null;
693 }
694 }
695
696 @Override
697 public void rollback(final Savepoint savepoint) throws SQLException {
698 checkOpen();
699 try {
700 connection.rollback(savepoint);
701 } catch (final SQLException e) {
702 handleException(e);
703 }
704 }
705
706 @Override
707 public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
708 checkOpen();
709 try {
710 connection.releaseSavepoint(savepoint);
711 } catch (final SQLException e) {
712 handleException(e);
713 }
714 }
715
716 @Override
717 public Statement createStatement(final int resultSetType, final int resultSetConcurrency,
718 final int resultSetHoldability) throws SQLException {
719 checkOpen();
720 try {
721 final DelegatingStatement ds = new DelegatingStatement(this,
722 connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));
723 initializeStatement(ds);
724 return ds;
725 } catch (final SQLException e) {
726 handleException(e);
727 return null;
728 }
729 }
730
731 @Override
732 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
733 final int resultSetHoldability) throws SQLException {
734 checkOpen();
735 try {
736 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
737 connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
738 initializeStatement(dps);
739 return dps;
740 } catch (final SQLException e) {
741 handleException(e);
742 return null;
743 }
744 }
745
746 @Override
747 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
748 final int resultSetHoldability) throws SQLException {
749 checkOpen();
750 try {
751 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this,
752 connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
753 initializeStatement(dcs);
754 return dcs;
755 } catch (final SQLException e) {
756 handleException(e);
757 return null;
758 }
759 }
760
761 @Override
762 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
763 checkOpen();
764 try {
765 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
766 connection.prepareStatement(sql, autoGeneratedKeys));
767 initializeStatement(dps);
768 return dps;
769 } catch (final SQLException e) {
770 handleException(e);
771 return null;
772 }
773 }
774
775 @Override
776 public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException {
777 checkOpen();
778 try {
779 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
780 connection.prepareStatement(sql, columnIndexes));
781 initializeStatement(dps);
782 return dps;
783 } catch (final SQLException e) {
784 handleException(e);
785 return null;
786 }
787 }
788
789 @Override
790 public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException {
791 checkOpen();
792 try {
793 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this,
794 connection.prepareStatement(sql, columnNames));
795 initializeStatement(dps);
796 return dps;
797 } catch (final SQLException e) {
798 handleException(e);
799 return null;
800 }
801 }
802
803 @Override
804 public boolean isWrapperFor(final Class<?> iface) throws SQLException {
805 if (iface.isAssignableFrom(getClass())) {
806 return true;
807 } else if (iface.isAssignableFrom(connection.getClass())) {
808 return true;
809 } else {
810 return connection.isWrapperFor(iface);
811 }
812 }
813
814 @Override
815 public <T> T unwrap(final Class<T> iface) throws SQLException {
816 if (iface.isAssignableFrom(getClass())) {
817 return iface.cast(this);
818 } else if (iface.isAssignableFrom(connection.getClass())) {
819 return iface.cast(connection);
820 } else {
821 return connection.unwrap(iface);
822 }
823 }
824
825 @Override
826 public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
827 checkOpen();
828 try {
829 return connection.createArrayOf(typeName, elements);
830 } catch (final SQLException e) {
831 handleException(e);
832 return null;
833 }
834 }
835
836 @Override
837 public Blob createBlob() throws SQLException {
838 checkOpen();
839 try {
840 return connection.createBlob();
841 } catch (final SQLException e) {
842 handleException(e);
843 return null;
844 }
845 }
846
847 @Override
848 public Clob createClob() throws SQLException {
849 checkOpen();
850 try {
851 return connection.createClob();
852 } catch (final SQLException e) {
853 handleException(e);
854 return null;
855 }
856 }
857
858 @Override
859 public NClob createNClob() throws SQLException {
860 checkOpen();
861 try {
862 return connection.createNClob();
863 } catch (final SQLException e) {
864 handleException(e);
865 return null;
866 }
867 }
868
869 @Override
870 public SQLXML createSQLXML() throws SQLException {
871 checkOpen();
872 try {
873 return connection.createSQLXML();
874 } catch (final SQLException e) {
875 handleException(e);
876 return null;
877 }
878 }
879
880 @Override
881 public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
882 checkOpen();
883 try {
884 return connection.createStruct(typeName, attributes);
885 } catch (final SQLException e) {
886 handleException(e);
887 return null;
888 }
889 }
890
891 @Override
892 public boolean isValid(final int timeoutSeconds) throws SQLException {
893 if (isClosed()) {
894 return false;
895 }
896 try {
897 return connection.isValid(timeoutSeconds);
898 } catch (final SQLException e) {
899 handleException(e);
900 return false;
901 }
902 }
903
904 @Override
905 public void setClientInfo(final String name, final String value) throws SQLClientInfoException {
906 try {
907 checkOpen();
908 connection.setClientInfo(name, value);
909 } catch (final SQLClientInfoException e) {
910 throw e;
911 } catch (final SQLException e) {
912 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e);
913 }
914 }
915
916 @Override
917 public void setClientInfo(final Properties properties) throws SQLClientInfoException {
918 try {
919 checkOpen();
920 connection.setClientInfo(properties);
921 } catch (final SQLClientInfoException e) {
922 throw e;
923 } catch (final SQLException e) {
924 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e);
925 }
926 }
927
928 @Override
929 public Properties getClientInfo() throws SQLException {
930 checkOpen();
931 try {
932 return connection.getClientInfo();
933 } catch (final SQLException e) {
934 handleException(e);
935 return null;
936 }
937 }
938
939 @Override
940 public String getClientInfo(final String name) throws SQLException {
941 checkOpen();
942 try {
943 return connection.getClientInfo(name);
944 } catch (final SQLException e) {
945 handleException(e);
946 return null;
947 }
948 }
949
950 @Override
951 public void setSchema(final String schema) throws SQLException {
952 checkOpen();
953 try {
954 Jdbc41Bridge.setSchema(connection, schema);
955 } catch (final SQLException e) {
956 handleException(e);
957 }
958 }
959
960 @Override
961 public String getSchema() throws SQLException {
962 checkOpen();
963 try {
964 return Jdbc41Bridge.getSchema(connection);
965 } catch (final SQLException e) {
966 handleException(e);
967 return null;
968 }
969 }
970
971 @Override
972 public void abort(final Executor executor) throws SQLException {
973 checkOpen();
974 try {
975 Jdbc41Bridge.abort(connection, executor);
976 } catch (final SQLException e) {
977 handleException(e);
978 }
979 }
980
981 @Override
982 public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
983 checkOpen();
984 try {
985 Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds);
986 } catch (final SQLException e) {
987 handleException(e);
988 }
989 }
990
991 @Override
992 public int getNetworkTimeout() throws SQLException {
993 checkOpen();
994 try {
995 return Jdbc41Bridge.getNetworkTimeout(connection);
996 } catch (final SQLException e) {
997 handleException(e);
998 return 0;
999 }
1000 }
1001 }
1002