You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by gn...@apache.org on 2014/06/17 13:25:34 UTC

svn commit: r1603130 - in /aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc: ./ internal/

Author: gnodet
Date: Tue Jun 17 11:25:34 2014
New Revision: 1603130

URL: http://svn.apache.org/r1603130
Log:
[ARIES-1211] Add connection validation feature to jdbc

Added:
    aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Reflections.java
    aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingDelegatingManagedConnectionFactory.java
    aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingGenericConnectionManager.java
Modified:
    aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java
    aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java
    aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java

Modified: aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java
URL: http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java?rev=1603130&r1=1603129&r2=1603130&view=diff
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java (original)
+++ aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/RecoverableDataSource.java Tue Jun 17 11:25:34 2014
@@ -59,6 +59,9 @@ public class RecoverableDataSource imple
     private int poolMaxSize = 10;
     private int poolMinSize = 0;
     private String transaction;
+    private boolean validateOnMatch = true;
+    private boolean backgroundValidation = false;
+    private int backgroundValidationMilliseconds = 600000;
 
     private DataSource delegate;
 
@@ -152,6 +155,30 @@ public class RecoverableDataSource imple
         this.poolMinSize = poolMinSize;
     }
 
+     /**
+     * If validation on connection matching is enabled (defaults to true).
+     * @param validateOnMatch
+     */
+    public void setValidateOnMatch(boolean validateOnMatch) {
+        this.validateOnMatch = validateOnMatch;
+    }
+
+    /**
+     * If periodically background validation is enabled (defaults to false).
+     * @param backgroundValidation
+     */
+    public void setBackgroundValidation(boolean backgroundValidation) {
+        this.backgroundValidation = backgroundValidation;
+    }
+
+    /**
+     * Background validation period (defaults to 600000)
+     * @param backgroundValidationMilliseconds
+     */
+    public void setBackgroundValidationMilliseconds(int backgroundValidationMilliseconds) {
+        this.backgroundValidationMilliseconds = backgroundValidationMilliseconds;
+    }
+
     /**
      * Transaction support.
      * Can be none, local or xa (defaults to xa).
@@ -194,6 +221,9 @@ public class RecoverableDataSource imple
         cm.setPooling(pooling);
         cm.setPoolMaxSize(poolMaxSize);
         cm.setPoolMinSize(poolMinSize);
+        cm.setValidateOnMatch(validateOnMatch);
+        cm.setBackgroundValidation(backgroundValidation);
+        cm.setBackgroundValidationMilliseconds(backgroundValidationMilliseconds);
         cm.setTransaction(transaction);
         cm.init();
 

Modified: aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java?rev=1603130&r1=1603129&r2=1603130&view=diff
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java (original)
+++ aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ConnectionManagerFactory.java Tue Jun 17 11:25:34 2014
@@ -32,6 +32,7 @@ import org.apache.geronimo.connector.out
 import org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTrackingCoordinator;
 import org.apache.geronimo.connector.outbound.connectiontracking.GeronimoTransactionListener;
 import org.apache.geronimo.transaction.manager.TransactionManagerMonitor;
+import org.tranql.connector.UserPasswordManagedConnectionFactory;
 
 import javax.resource.spi.ConnectionManager;
 import javax.resource.spi.ManagedConnectionFactory;
@@ -53,6 +54,10 @@ public class ConnectionManagerFactory {
     private int connectionMaxWaitMilliseconds = 5000;
     private int connectionMaxIdleMinutes = 15;
 
+    private boolean validateOnMatch = true;
+    private boolean backgroundValidation = false;
+    private int backgroundValidationMilliseconds = 600000;
+
     private SubjectSource subjectSource;
 
     private ConnectionTrackingCoordinator connectionTracker;
@@ -136,16 +141,34 @@ public class ConnectionManagerFactory {
             transactionManager.addTransactionAssociationListener(transactionManagerMonitor);
         }
         if (connectionManager == null) {
-            // Instantiate the Geronimo Connection Manager
-            connectionManager = new GenericConnectionManager(
-                    transactionSupport,
-                    poolingSupport,
-                    subjectSource,
-                    connectionTracker,
-                    transactionManager,
-                    managedConnectionFactory,
-                    getClass().getName(),
-                    getClass().getClassLoader());
+            if (validateOnMatch || backgroundValidation) {
+                // Wrap the original ManagedConnectionFactory to add validation capability
+                managedConnectionFactory = new ValidatingDelegatingManagedConnectionFactory((UserPasswordManagedConnectionFactory) managedConnectionFactory);
+            }
+            if (backgroundValidation) {
+                // Instantiate the Validating Connection Manager
+                connectionManager = new ValidatingGenericConnectionManager(
+                        transactionSupport,
+                        poolingSupport,
+                        subjectSource,
+                        connectionTracker,
+                        transactionManager,
+                        managedConnectionFactory,
+                        getClass().getName(),
+                        getClass().getClassLoader(),
+                        backgroundValidationMilliseconds);
+            } else {
+                // Instantiate the Geronimo Connection Manager
+                connectionManager = new GenericConnectionManager(
+                        transactionSupport,
+                        poolingSupport,
+                        subjectSource,
+                        connectionTracker,
+                        transactionManager,
+                        managedConnectionFactory,
+                        getClass().getName(),
+                        getClass().getClassLoader());
+            }
 
             connectionManager.doStart();
         }
@@ -257,6 +280,30 @@ public class ConnectionManagerFactory {
         this.connectionMaxIdleMinutes = connectionMaxIdleMinutes;
     }
 
+    public boolean isValidateOnMatch() {
+        return validateOnMatch;
+    }
+
+    public void setValidateOnMatch(boolean validateOnMatch) {
+        this.validateOnMatch = validateOnMatch;
+    }
+
+    public boolean isBackgroundValidation() {
+        return backgroundValidation;
+    }
+
+    public void setBackgroundValidation(boolean backgroundValidation) {
+        this.backgroundValidation = backgroundValidation;
+    }
+
+    public int getBackgroundValidationMilliseconds() {
+        return backgroundValidationMilliseconds;
+    }
+
+    public void setBackgroundValidationMilliseconds(int backgroundValidationMilliseconds) {
+        this.backgroundValidationMilliseconds = backgroundValidationMilliseconds;
+    }
+
     public SubjectSource getSubjectSource() {
         return subjectSource;
     }

Modified: aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java?rev=1603130&r1=1603129&r2=1603130&view=diff
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java (original)
+++ aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ManagedDataSourceFactory.java Tue Jun 17 11:25:34 2014
@@ -112,6 +112,9 @@ public class ManagedDataSourceFactory {
         cm.setPooling(getBool("aries.xa.pooling", true));
         cm.setPoolMaxSize(getInt("aries.xa.poolMaxSize", 10));
         cm.setPoolMinSize(getInt("aries.xa.poolMinSize", 0));
+        cm.setValidateOnMatch(getBool("aries.xa.validateOnMatch", true));
+        cm.setBackgroundValidation(getBool("aries.xa.backgroundValidation", false));
+        cm.setBackgroundValidationMilliseconds(getInt("aries.xa.backgroundValidationMilliseconds", 600000));
         cm.setTransaction(getString("aries.xa.transaction", "xa"));
         cm.init();
 

Added: aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Reflections.java
URL: http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Reflections.java?rev=1603130&view=auto
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Reflections.java (added)
+++ aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/Reflections.java Tue Jun 17 11:25:34 2014
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.transaction.jdbc.internal;
+
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+public final class Reflections {
+
+    private Reflections() {
+        // no-op
+    }
+
+    public static Object get(final Object instance, String field) {
+        Class<?> clazz = instance.getClass();
+        while (clazz != null) {
+            try {
+                final Field f = clazz.getDeclaredField(field);
+                final boolean acc = f.isAccessible();
+                return AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        f.setAccessible(true);
+                        try {
+                            return f.get(instance);
+                        } catch (IllegalAccessException ex) {
+                            throw new IllegalArgumentException(ex);
+                        } finally {
+                            f.setAccessible(acc);
+                        }
+                    }
+                });
+            } catch (NoSuchFieldException nsfe) {
+                // no-op
+            }
+
+            clazz = clazz.getSuperclass();
+        }
+        throw new RuntimeException(new NoSuchFieldException(field));
+    }
+}

Added: aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingDelegatingManagedConnectionFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingDelegatingManagedConnectionFactory.java?rev=1603130&view=auto
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingDelegatingManagedConnectionFactory.java (added)
+++ aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingDelegatingManagedConnectionFactory.java Tue Jun 17 11:25:34 2014
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.transaction.jdbc.internal;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.tranql.connector.AbstractManagedConnection;
+import org.tranql.connector.ManagedConnectionHandle;
+import org.tranql.connector.UserPasswordManagedConnectionFactory;
+import org.tranql.connector.jdbc.ConnectionHandle;
+import org.tranql.connector.jdbc.TranqlDataSource;
+
+import javax.resource.NotSupportedException;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.TransactionSupport;
+import javax.resource.spi.ValidatingManagedConnectionFactory;
+import javax.security.auth.Subject;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+
+public final class ValidatingDelegatingManagedConnectionFactory implements UserPasswordManagedConnectionFactory, ValidatingManagedConnectionFactory, TransactionSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ValidatingDelegatingManagedConnectionFactory.class);
+    private final ManagedConnectionFactory delegate;
+
+    public ValidatingDelegatingManagedConnectionFactory(ManagedConnectionFactory managedConnectionFactory) {
+        this.delegate = managedConnectionFactory;
+    }
+
+    private boolean isValidConnection(Connection c) {
+        try {
+            if (c.isValid(0)) {
+                LOG.debug("Connection validation succeeded for managed connection {}.", c);
+                return true;
+            } else {
+                LOG.debug("Connection validation failed for managed connection {}.", c);
+            }
+        } catch (SQLException e) {
+            // no-op
+        }
+        return false;
+    }
+
+    @Override
+    public TransactionSupportLevel getTransactionSupport() {
+        return TransactionSupport.class.cast(delegate).getTransactionSupport();
+    }
+
+    @Override
+    public Set getInvalidConnections(Set connectionSet) throws ResourceException {
+        Set<ManagedConnection> invalid = new HashSet<ManagedConnection>();
+
+        for (Object o : connectionSet) {
+            if (o instanceof AbstractManagedConnection) {
+                AbstractManagedConnection<Connection, ConnectionHandle> amc = AbstractManagedConnection.class.cast(o);
+
+                if (!isValidConnection(amc.getPhysicalConnection())) {
+                    invalid.add(amc);
+                }
+            }
+        }
+
+        return invalid;
+    }
+
+    @Override
+    public String getUserName() {
+        return UserPasswordManagedConnectionFactory.class.cast(delegate).getUserName();
+    }
+
+    @Override
+    public String getPassword() {
+        return UserPasswordManagedConnectionFactory.class.cast(delegate).getPassword();
+    }
+
+    @Override
+    public Object createConnectionFactory(ConnectionManager cxManager) throws ResourceException {
+        return new TranqlDataSource(this, cxManager);
+    }
+
+    @Override
+    public Object createConnectionFactory() throws ResourceException {
+        throw new NotSupportedException("ConnectionManager is required");
+    }
+
+    @Override
+    public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException {
+        return delegate.createManagedConnection(subject, cxRequestInfo);
+    }
+
+    @Override
+    public ManagedConnection matchManagedConnections(Set connectionSet, Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException {
+        for (Object o : connectionSet) {
+            if (o instanceof ManagedConnectionHandle) {
+                ManagedConnectionHandle mch = ManagedConnectionHandle.class.cast(o);
+                if (mch.matches(this, subject, cxRequestInfo)) {
+                    if (mch instanceof AbstractManagedConnection) {
+                        AbstractManagedConnection<Connection, ConnectionHandle> amc = AbstractManagedConnection.class.cast(mch);
+                        if (isValidConnection(amc.getPhysicalConnection())) {
+                            return amc;
+                        }
+                    } else {
+                        return mch;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public void setLogWriter(PrintWriter out) throws ResourceException {
+        delegate.setLogWriter(out);
+    }
+
+    @Override
+    public PrintWriter getLogWriter() throws ResourceException {
+        return delegate.getLogWriter();
+    }
+
+    @Override
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return delegate.equals(other);
+    }
+}

Added: aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingGenericConnectionManager.java
URL: http://svn.apache.org/viewvc/aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingGenericConnectionManager.java?rev=1603130&view=auto
==============================================================================
--- aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingGenericConnectionManager.java (added)
+++ aries/trunk/transaction/transaction-jdbc/src/main/java/org/apache/aries/transaction/jdbc/internal/ValidatingGenericConnectionManager.java Tue Jun 17 11:25:34 2014
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.transaction.jdbc.internal;
+
+import org.apache.geronimo.connector.outbound.AbstractSinglePoolConnectionInterceptor;
+import org.apache.geronimo.connector.outbound.ConnectionInfo;
+import org.apache.geronimo.connector.outbound.ConnectionInterceptor;
+import org.apache.geronimo.connector.outbound.ConnectionReturnAction;
+import org.apache.geronimo.connector.outbound.GenericConnectionManager;
+import org.apache.geronimo.connector.outbound.ManagedConnectionInfo;
+import org.apache.geronimo.connector.outbound.MultiPoolConnectionInterceptor;
+import org.apache.geronimo.connector.outbound.SinglePoolConnectionInterceptor;
+import org.apache.geronimo.connector.outbound.SinglePoolMatchAllConnectionInterceptor;
+import org.apache.geronimo.connector.outbound.SubjectSource;
+import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport;
+import org.apache.geronimo.connector.outbound.connectionmanagerconfig.TransactionSupport;
+import org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTracker;
+import org.apache.geronimo.transaction.manager.RecoverableTransactionManager;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.ValidatingManagedConnectionFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.locks.ReadWriteLock;
+
+public final class ValidatingGenericConnectionManager extends GenericConnectionManager {
+
+    private static final Timer TIMER = new Timer("ValidatingGenericConnectionManagerTimer", true);
+
+    private transient final TimerTask validatingTask;
+    private final long validatingInterval;
+
+    private final ReadWriteLock lock;
+    private final Object pool;
+
+    public ValidatingGenericConnectionManager(TransactionSupport transactionSupport, PoolingSupport pooling, SubjectSource subjectSource, ConnectionTracker connectionTracker, RecoverableTransactionManager transactionManager, ManagedConnectionFactory mcf, String name, ClassLoader classLoader, long interval) {
+        super(transactionSupport, pooling, subjectSource, connectionTracker, transactionManager, mcf, name, classLoader);
+        validatingInterval = interval;
+
+        ConnectionInterceptor stack = interceptors.getStack();
+
+        ReadWriteLock foundLock = null;
+        ConnectionInterceptor current = stack;
+        do {
+            if (current instanceof AbstractSinglePoolConnectionInterceptor) {
+                try {
+                    foundLock = (ReadWriteLock) Reflections.get(current, "resizeLock");
+                } catch (Exception e) {
+                    // no-op
+                }
+                break;
+            }
+
+            // look next
+            try {
+                current = (ConnectionInterceptor) Reflections.get(current, "next");
+            } catch (Exception e) {
+                current = null;
+            }
+        } while (current != null);
+
+        this.lock = foundLock;
+
+        Object foundPool = null;
+        if (current instanceof AbstractSinglePoolConnectionInterceptor) {
+            foundPool = Reflections.get(stack, "pool");
+        } else if (current instanceof MultiPoolConnectionInterceptor) {
+            log.warn("validation on stack {} not supported", stack);
+        }
+        this.pool = foundPool;
+
+        if (pool != null) {
+            validatingTask = new ValidatingTask(current, lock, pool);
+        } else {
+            validatingTask = null;
+        }
+    }
+
+    @Override
+    public void doStart() throws Exception {
+        super.doStart();
+        if (validatingTask != null) {
+            TIMER.schedule(validatingTask, validatingInterval, validatingInterval);
+        }
+    }
+
+    @Override
+    public void doStop() throws Exception {
+        if (validatingTask != null) {
+            validatingTask.cancel();
+        }
+        super.doStop();
+    }
+
+    private class ValidatingTask extends TimerTask {
+
+        private final ConnectionInterceptor stack;
+        private final ReadWriteLock lock;
+        private final Object pool;
+
+        public ValidatingTask(ConnectionInterceptor stack, ReadWriteLock lock, Object pool) {
+            this.stack = stack;
+            this.lock = lock;
+            this.pool = pool;
+        }
+
+        @Override
+        public void run() {
+            if (lock != null) {
+                lock.writeLock().lock();
+            }
+
+            try {
+                final Map<ManagedConnection, ManagedConnectionInfo> connections;
+                if (stack instanceof SinglePoolConnectionInterceptor) {
+                    connections = new HashMap<ManagedConnection, ManagedConnectionInfo>();
+                    for (ManagedConnectionInfo info : (List<ManagedConnectionInfo>) pool) {
+                        connections.put(info.getManagedConnection(), info);
+                    }
+                } else if (stack instanceof SinglePoolMatchAllConnectionInterceptor) {
+                    connections = (Map<ManagedConnection, ManagedConnectionInfo>) pool;
+                } else {
+                    log.warn("stack {} currently not supported", stack);
+                    return;
+                }
+
+                // destroy invalid connections
+                try {
+                    Set<ManagedConnection> invalids = ValidatingManagedConnectionFactory.class.cast(getManagedConnectionFactory()).getInvalidConnections(connections.keySet());
+                    if (invalids != null) {
+                        for (ManagedConnection invalid : invalids) {
+                            stack.returnConnection(new ConnectionInfo(connections.get(invalid)), ConnectionReturnAction.DESTROY);
+                        }
+                    }
+                } catch (ResourceException e) {
+                    log.error(e.getMessage(), e);
+                }
+            } finally {
+                if (lock != null) {
+                    lock.writeLock().unlock();
+                }
+            }
+        }
+    }
+}