geronimo-scm mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject svn commit: r494504 - in /geronimo/server/branches/1.2/modules/geronimo-connector/src: main/java/org/apache/geronimo/connector/outbound/ main/java/org/apache/geronimo/connector/outbound/connectiontracking/ test/java/org/apache/geronimo/connector/mock/ ...
Date Tue, 09 Jan 2007 18:02:34 GMT
Author: dain
Date: Tue Jan  9 10:02:32 2007
New Revision: 494504

URL: http://svn.apache.org/viewvc?view=rev&rev=494504
Log:
GERONIMO-2715 Added support for Connector Lazy Activation

Added:
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/ConnectionExtension.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorProxyTest.java
Modified:
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/AbstractConnectionManager.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionInfo.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptor.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTracker.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinator.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorGBean.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/TrackedConnectionAssociator.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnection.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnectionFactory.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTest.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTestUtils.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptorTest.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ManagedConnectionFactoryWrapperTest.java
    geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorTest.java

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/AbstractConnectionManager.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/AbstractConnectionManager.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/AbstractConnectionManager.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/AbstractConnectionManager.java Tue Jan  9 10:02:32 2007
@@ -59,7 +59,11 @@
         ManagedConnectionInfo mci = new ManagedConnectionInfo(managedConnectionFactory, connectionRequestInfo);
         ConnectionInfo ci = new ConnectionInfo(mci);
         getStack().getConnection(ci);
-        return ci.getConnectionHandle();
+        Object connection = ci.getConnectionProxy();
+        if (connection == null) {
+            connection = ci.getConnectionHandle();
+        }
+        return connection;
     }
 
     /**

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionInfo.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionInfo.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionInfo.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionInfo.java Tue Jan  9 10:02:32 2007
@@ -29,6 +29,7 @@
 
     private ManagedConnectionInfo mci;
     private Object connection;
+    private Object connectionProxy;
     private boolean unshareable;
     private boolean applicationManagedSecurity;
     private Exception trace;
@@ -71,6 +72,14 @@
     public void setConnectionHandle(Object connection) {
         assert this.connection == null;
         this.connection = connection;
+    }
+
+    public Object getConnectionProxy() {
+        return connectionProxy;
+    }
+
+    public void setConnectionProxy(Object connectionProxy) {
+        this.connectionProxy = connectionProxy;
     }
 
     public boolean isUnshareable() {

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptor.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptor.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptor.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptor.java Tue Jan  9 10:02:32 2007
@@ -64,7 +64,16 @@
     public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
         connectionTracker.setEnvironment(connectionInfo, key);
         next.getConnection(connectionInfo);
-        connectionTracker.handleObtained(this, connectionInfo);
+        connectionTracker.handleObtained(this, connectionInfo, false);
+    }
+
+    /**
+     * Called when a proxied connection which has been released need to be reassociated with a real connection.
+     */
+    public void reassociateConnection(ConnectionInfo connectionInfo) throws ResourceException {
+        connectionTracker.setEnvironment(connectionInfo, key);
+        next.getConnection(connectionInfo);
+        connectionTracker.handleObtained(this, connectionInfo, true);
     }
 
     /**
@@ -78,7 +87,7 @@
     public void returnConnection(
             ConnectionInfo connectionInfo,
             ConnectionReturnAction connectionReturnAction) {
-        connectionTracker.handleReleased(this, connectionInfo);
+        connectionTracker.handleReleased(this, connectionInfo, connectionReturnAction);
         next.returnConnection(connectionInfo, connectionReturnAction);
     }
 
@@ -107,9 +116,7 @@
             ManagedConnection managedConnection = managedConnectionInfo.getManagedConnection();
             if (managedConnection instanceof DissociatableManagedConnection
                     && managedConnectionInfo.isFirstConnectionInfo(connectionInfo)) {
-                int size = connectionInfos.size();
                 i.remove();
-                assert size - 1 == connectionInfos.size();
                 ((DissociatableManagedConnection) managedConnection).dissociateConnections();
                 managedConnectionInfo.clearConnectionHandles();
                 //todo this needs some kind of check so cx isn't returned more than once

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTracker.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTracker.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTracker.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTracker.java Tue Jan  9 10:02:32 2007
@@ -19,6 +19,9 @@
 
 import org.apache.geronimo.connector.outbound.ConnectionInfo;
 import org.apache.geronimo.connector.outbound.ConnectionTrackingInterceptor;
+import org.apache.geronimo.connector.outbound.ConnectionReturnAction;
+
+import javax.resource.ResourceException;
 
 /**
  *
@@ -29,12 +32,13 @@
 public interface ConnectionTracker {
     void handleObtained(
             ConnectionTrackingInterceptor connectionTrackingInterceptor,
-            ConnectionInfo connectionInfo);
+            ConnectionInfo connectionInfo,
+            boolean reassociate) throws ResourceException;
 
     void handleReleased(
             ConnectionTrackingInterceptor connectionTrackingInterceptor,
-            ConnectionInfo connectionInfo);
+            ConnectionInfo connectionInfo,
+            ConnectionReturnAction connectionReturnAction);
 
     void setEnvironment(ConnectionInfo connectionInfo, String key);
-
 }

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinator.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinator.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinator.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinator.java Tue Jan  9 10:02:32 2007
@@ -22,13 +22,19 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
 import javax.resource.ResourceException;
 
 import org.apache.geronimo.connector.outbound.ConnectionInfo;
 import org.apache.geronimo.connector.outbound.ConnectionTrackingInterceptor;
 import org.apache.geronimo.connector.outbound.ManagedConnectionInfo;
+import org.apache.geronimo.connector.outbound.ConnectionReturnAction;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentMap;
+import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
 
 /**
  * ConnectionTrackingCoordinator tracks connections that are in use by
@@ -49,103 +55,295 @@
 public class ConnectionTrackingCoordinator implements TrackedConnectionAssociator, ConnectionTracker {
     private static final Log log = LogFactory.getLog(ConnectionTrackingCoordinator.class.getName());
 
+    private final boolean lazyConnect;
     private final ThreadLocal currentInstanceContexts = new ThreadLocal();
+    private final ConcurrentMap proxiesByConnectionInfo = new ConcurrentHashMap();
 
-    public ConnectorInstanceContext enter(ConnectorInstanceContext newConnectorInstanceContext)
-            throws ResourceException {
-        ConnectorInstanceContext oldConnectorInstanceContext = (ConnectorInstanceContext) currentInstanceContexts.get();
-        currentInstanceContexts.set(newConnectorInstanceContext);
-        notifyConnections(newConnectorInstanceContext);
-        return oldConnectorInstanceContext;
-    }
-
-    private void notifyConnections(ConnectorInstanceContext oldConnectorInstanceContext) throws ResourceException {
-        Map connectionManagerToManagedConnectionInfoMap = oldConnectorInstanceContext.getConnectionManagerMap();
-        for (Iterator i = connectionManagerToManagedConnectionInfoMap.entrySet().iterator(); i.hasNext();) {
-            Map.Entry entry = (Map.Entry) i.next();
-            ConnectionTrackingInterceptor mcci =
-                    (ConnectionTrackingInterceptor) entry.getKey();
-            Set connections = (Set) entry.getValue();
-            mcci.enter(connections);
+    public ConnectionTrackingCoordinator() {
+        this(false);
+    }
+
+    public ConnectionTrackingCoordinator(boolean lazyConnect) {
+        this.lazyConnect = lazyConnect;
+    }
+
+    public boolean isLazyConnect() {
+        return lazyConnect;
+    }
+
+    public ConnectorInstanceContext enter(ConnectorInstanceContext newContext) throws ResourceException {
+        ConnectorInstanceContext oldContext = (ConnectorInstanceContext) currentInstanceContexts.get();
+        currentInstanceContexts.set(newContext);
+        associateConnections(newContext);
+        return oldContext;
+    }
+
+    private void associateConnections(ConnectorInstanceContext context) throws ResourceException {
+        if (!lazyConnect) {
+            Map connectionManagerToManagedConnectionInfoMap = context.getConnectionManagerMap();
+            for (Iterator i = connectionManagerToManagedConnectionInfoMap.entrySet().iterator(); i.hasNext();) {
+                Map.Entry entry = (Map.Entry) i.next();
+                ConnectionTrackingInterceptor mcci =
+                        (ConnectionTrackingInterceptor) entry.getKey();
+                Set connections = (Set) entry.getValue();
+                mcci.enter(connections);
+            }
         }
     }
 
     public void newTransaction() throws ResourceException {
-        ConnectorInstanceContext oldConnectorInstanceContext = (ConnectorInstanceContext) currentInstanceContexts.get();
-        if (oldConnectorInstanceContext == null) {
+        ConnectorInstanceContext currentContext = (ConnectorInstanceContext) currentInstanceContexts.get();
+        if (currentContext == null) {
             return;
         }
-        notifyConnections(oldConnectorInstanceContext);
+        associateConnections(currentContext);
     }
 
-    public void exit(ConnectorInstanceContext reenteringConnectorInstanceContext)
-            throws ResourceException {
-        ConnectorInstanceContext oldConnectorInstanceContext = (ConnectorInstanceContext) currentInstanceContexts.get();
-        Map resources = oldConnectorInstanceContext.getConnectionManagerMap();
-        for (Iterator i = resources.entrySet().iterator(); i.hasNext();) {
-            Map.Entry entry = (Map.Entry) i.next();
-            ConnectionTrackingInterceptor mcci =
-                    (ConnectionTrackingInterceptor) entry.getKey();
-            Set connections = (Set) entry.getValue();
-            mcci.exit(connections);
-            if (connections.isEmpty()) {
-                i.remove();
+    public void exit(ConnectorInstanceContext oldContext) throws ResourceException {
+        ConnectorInstanceContext currentContext = (ConnectorInstanceContext) currentInstanceContexts.get();
+        try {
+            // for each connection type opened in this componet
+            Map resources = currentContext.getConnectionManagerMap();
+            for (Iterator i = resources.entrySet().iterator(); i.hasNext();) {
+                Map.Entry entry = (Map.Entry) i.next();
+                ConnectionTrackingInterceptor mcci =
+                        (ConnectionTrackingInterceptor) entry.getKey();
+                Set connections = (Set) entry.getValue();
+
+                // use connection interceptor to dissociate connections that support disassociation
+                mcci.exit(connections);
+
+                // if no connection remain clear context... we could support automatic commit, rollback or exception here
+                if (connections.isEmpty()) {
+                    i.remove();
+                }
             }
+        } finally {
+            // when lazy we do not need or want to track open connections... they will automatically reconnect
+            if (lazyConnect) {
+                currentContext.getConnectionManagerMap().clear();
+            }
+            currentInstanceContexts.set(oldContext);
         }
-        currentInstanceContexts.set(reenteringConnectorInstanceContext);
     }
 
+    /**
+     * A new connection (handle) has been obtained.  If we are within a component context, store the connection handle
+     * so we can disassociate connections that support disassociation on exit.
+     * @param connectionTrackingInterceptor our interceptor in the connection manager which is used to disassociate the connections
+     * @param connectionInfo the connection that was obtained
+     * @param reassociate
+     */
+    public void handleObtained(ConnectionTrackingInterceptor connectionTrackingInterceptor,
+            ConnectionInfo connectionInfo,
+            boolean reassociate) throws ResourceException {
 
-    public void handleObtained(
-            ConnectionTrackingInterceptor connectionTrackingInterceptor,
-            ConnectionInfo connectionInfo) {
-        ConnectorInstanceContext connectorInstanceContext = (ConnectorInstanceContext) currentInstanceContexts.get();
-        if (connectorInstanceContext == null) {
+        ConnectorInstanceContext currentContext = (ConnectorInstanceContext) currentInstanceContexts.get();
+        if (currentContext == null) {
             return;
         }
-        Map resources = connectorInstanceContext.getConnectionManagerMap();
+
+        Map resources = currentContext.getConnectionManagerMap();
         Set infos = (Set) resources.get(connectionTrackingInterceptor);
         if (infos == null) {
             infos = new HashSet();
             resources.put(connectionTrackingInterceptor, infos);
         }
+
         infos.add(connectionInfo);
+
+        // if lazyConnect, we must proxy so we know when to connect the proxy
+        if (!reassociate && lazyConnect) {
+            proxyConnection(connectionTrackingInterceptor, connectionInfo);
+        }
     }
 
-    public void handleReleased(
-            ConnectionTrackingInterceptor connectionTrackingInterceptor,
-            ConnectionInfo connectionInfo) {
-        ConnectorInstanceContext connectorInstanceContext = (ConnectorInstanceContext) currentInstanceContexts.get();
-        if (connectorInstanceContext == null) {
+    /**
+     * A connection (handle) has been released or destroyed.  If we are within a component context, remove the connection
+     * handle from the context.
+     * @param connectionTrackingInterceptor our interceptor in the connection manager
+     * @param connectionInfo the connection that was released
+     * @param connectionReturnAction
+     */
+    public void handleReleased(ConnectionTrackingInterceptor connectionTrackingInterceptor,
+            ConnectionInfo connectionInfo,
+            ConnectionReturnAction connectionReturnAction) {
+
+        ConnectorInstanceContext currentContext = (ConnectorInstanceContext) currentInstanceContexts.get();
+        if (currentContext == null) {
             return;
         }
-        Map resources = connectorInstanceContext.getConnectionManagerMap();
+
+        Map resources = currentContext.getConnectionManagerMap();
         Set infos = (Set) resources.get(connectionTrackingInterceptor);
-        if (infos == null) {
-            if (log.isTraceEnabled()) {
-                log.trace("No infos found for handle " + connectionInfo.getConnectionHandle() + " for MCI: " + connectionInfo.getManagedConnectionInfo() + " for MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " for CTI: " + connectionTrackingInterceptor, new Exception("Stack Trace"));
+        if (infos != null) {
+            if (connectionInfo.getConnectionHandle() == null) {
+                //destroy was called as a result of an error
+                ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
+                Collection toRemove = mci.getConnectionInfos();
+                infos.removeAll(toRemove);
+            } else {
+                infos.remove(connectionInfo);
             }
-        }
-        if (connectionInfo.getConnectionHandle() == null) {
-            //destroy was called as a result of an error
-            ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
-            Collection toRemove = mci.getConnectionInfos();
-            infos.removeAll(toRemove);
         } else {
-            infos.remove(connectionInfo);
+            if ( log.isTraceEnabled()) {
+                 log.trace("No infos found for handle " + connectionInfo.getConnectionHandle() +
+                         " for MCI: " + connectionInfo.getManagedConnectionInfo() +
+                         " for MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() +
+                         " for CTI: " + connectionTrackingInterceptor, new Exception("Stack Trace"));
+            }
+        }
+
+        if (lazyConnect) {
+            releaseProxyConnection(connectionInfo, connectionReturnAction);
         }
     }
 
+    /**
+     * If we are within a component context, before a connection is obtained, set the connection unshareable and
+     * applicationManagedSecurity properties so the correct connection type is obtained.
+     * @param connectionInfo the connection to be obtained
+     * @param key the unique id of the connection manager
+     */
     public void setEnvironment(ConnectionInfo connectionInfo, String key) {
-        ConnectorInstanceContext currentConnectorInstanceContext = (ConnectorInstanceContext) currentInstanceContexts.get();
-        if (currentConnectorInstanceContext != null) {
-            Set unshareableResources = currentConnectorInstanceContext.getUnshareableResources();
+        ConnectorInstanceContext currentContext = (ConnectorInstanceContext) currentInstanceContexts.get();
+        if (currentContext != null) {
+            // is this resource unshareable in this component context
+            Set unshareableResources = currentContext.getUnshareableResources();
             boolean unshareable = unshareableResources.contains(key);
             connectionInfo.setUnshareable(unshareable);
-            Set applicationManagedSecurityResources = currentConnectorInstanceContext.getApplicationManagedSecurityResources();
+
+            // does this resource use application managed security in this component context
+            Set applicationManagedSecurityResources = currentContext.getApplicationManagedSecurityResources();
             boolean applicationManagedSecurity = applicationManagedSecurityResources.contains(key);
             connectionInfo.setApplicationManagedSecurity(applicationManagedSecurity);
         }
     }
 
+    private void proxyConnection(ConnectionTrackingInterceptor connectionTrackingInterceptor, ConnectionInfo connectionInfo) throws ResourceException {
+        // if this connection already has a proxy no need to create another
+        if (connectionInfo.getConnectionProxy() != null) return;
+
+        try {
+            Object handle = connectionInfo.getConnectionHandle();
+            ConnectionInvocationHandler invocationHandler = new ConnectionInvocationHandler(connectionTrackingInterceptor, connectionInfo, handle);
+            Object proxy = Proxy.newProxyInstance(getClassLoader(handle), handle.getClass().getInterfaces(), invocationHandler);
+
+            // add it to our map... if the map already has a proxy for this connection, use the existing one
+            Object existingProxy = proxiesByConnectionInfo.putIfAbsent(connectionInfo, proxy);
+            if (existingProxy != null) proxy = existingProxy;
+
+            connectionInfo.setConnectionProxy(proxy);
+        } catch (Throwable e) {
+            throw new ResourceException("Unable to construct connection proxy", e);
+        }
+    }
+
+    private void releaseProxyConnection(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction) {
+        Object proxy = connectionInfo.getConnectionProxy();
+        if (proxy == null) {
+            proxy = proxiesByConnectionInfo.get(connectionInfo);
+        }
+        if (proxy == null) {
+            // no proxy or proxy alreayd destroyed
+            return;
+        }
+
+        ConnectionInvocationHandler invocationHandler = getConnectionInvocationHandler(proxy);
+        if (invocationHandler != null) {
+            if (connectionReturnAction == ConnectionReturnAction.RETURN_HANDLE) {
+                invocationHandler.releaseHandle();
+            } else if (connectionReturnAction == ConnectionReturnAction.DESTROY) {
+                invocationHandler.destroy();
+                proxiesByConnectionInfo.remove(connectionInfo);
+                connectionInfo.setConnectionProxy(null);
+            } else {
+                throw new IllegalArgumentException("Unknown ConnectionReturnAction " + connectionReturnAction);
+            }
+        }
+    }
+
+    // Favor the thread context class loader for proxy construction
+    private ClassLoader getClassLoader(Object handle) {
+        ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader();
+        if (threadClassLoader != null) {
+            return threadClassLoader;
+        }
+        return handle.getClass().getClassLoader();
+    }
+
+    private static ConnectionInvocationHandler getConnectionInvocationHandler(Object handle) {
+        if (handle == null) return null;
+
+        if (Proxy.isProxyClass(handle.getClass())) {
+            InvocationHandler invocationHandler = Proxy.getInvocationHandler(handle);
+            if (invocationHandler instanceof ConnectionInvocationHandler) {
+                return (ConnectionInvocationHandler) invocationHandler;
+            }
+        }
+        return null;
+    }
+
+    public static class ConnectionInvocationHandler implements InvocationHandler {
+        private ConnectionTrackingInterceptor connectionTrackingInterceptor;
+        private ConnectionInfo connectionInfo;
+        private Object handle;
+        private boolean released = false;
+
+        public ConnectionInvocationHandler(ConnectionTrackingInterceptor connectionTrackingInterceptor, ConnectionInfo connectionInfo, Object handle) {
+            this.connectionTrackingInterceptor = connectionTrackingInterceptor;
+            this.connectionInfo = connectionInfo;
+            this.handle = handle;
+        }
+
+        public Object invoke(Object object, Method method, Object[] args) throws Throwable {
+            Object handle;
+            if (method.getDeclaringClass() == Object.class) {
+                if (method.getName().equals("finalize")) {
+                    // ignore the handle will get called if it implemented the method
+                    return null;
+                }
+                if (method.getName().equals("clone")) {
+                    throw new CloneNotSupportedException();
+                }
+                // for equals, hashCode and toString don't activate handle
+                synchronized (this) {
+                    handle = this.handle;
+                }
+            } else {
+                handle = getHandle();
+            }
+            Object value = method.invoke(handle, args);
+            return value;
+        }
+
+        public synchronized boolean isReleased() {
+            return released;
+        }
+
+        public synchronized void releaseHandle() {
+            released = true;
+        }
+
+        public synchronized void destroy() {
+            connectionTrackingInterceptor = null;
+            connectionInfo = null;
+            handle = null;
+        }
+
+        public synchronized Object getHandle() {
+            if (connectionTrackingInterceptor == null) {
+                throw new IllegalStateException("Connection has been destroyed");
+            }
+            if (released) {
+                try {
+                    connectionTrackingInterceptor.reassociateConnection(connectionInfo);
+                } catch (ResourceException e) {
+                    throw (IllegalStateException) new IllegalStateException("Could not obtain a physical connection").initCause(e);
+                }
+                released = false;
+            }
+            return handle;
+        }
+    }
 }

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorGBean.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorGBean.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorGBean.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorGBean.java Tue Jan  9 10:02:32 2007
@@ -31,7 +31,8 @@
     private final MonitorableTransactionManager monitorableTm;
     private final GeronimoTransactionListener listener;
 
-    public ConnectionTrackingCoordinatorGBean(MonitorableTransactionManager monitorableTm) {
+    public ConnectionTrackingCoordinatorGBean(MonitorableTransactionManager monitorableTm, boolean lazyConnect) {
+        super(lazyConnect);
         this.monitorableTm = monitorableTm;
         listener = new GeronimoTransactionListener(this);
     }
@@ -54,11 +55,12 @@
         GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(ConnectionTrackingCoordinatorGBean.class, NameFactory.JCA_CONNECTION_TRACKER);
 
         infoFactory.addReference("TransactionManager", MonitorableTransactionManager.class, NameFactory.TRANSACTION_MANAGER);
+        infoFactory.addAttribute("lazyConnect", boolean.class, true);
 
         infoFactory.addInterface(TrackedConnectionAssociator.class);
         infoFactory.addInterface(ConnectionTracker.class);
 
-        infoFactory.setConstructor(new String[] {"TransactionManager"});
+        infoFactory.setConstructor(new String[] {"TransactionManager", "lazyConnect"});
         GBEAN_INFO = infoFactory.getBeanInfo();
     }
 

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/TrackedConnectionAssociator.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/TrackedConnectionAssociator.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/TrackedConnectionAssociator.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/main/java/org/apache/geronimo/connector/outbound/connectiontracking/TrackedConnectionAssociator.java Tue Jan  9 10:02:32 2007
@@ -26,13 +26,16 @@
  *
  */
 public interface TrackedConnectionAssociator {
+    /**
+     * If true, ConnectorInstanceContext instance does not have to be kept on a per component basis; otherwise the
+     * same instance must be passed to enter each time the specific component instance is entered.
+     * @return true if connections are proxied and only connect when invoked
+     */
+    boolean isLazyConnect();
 
-    ConnectorInstanceContext enter(ConnectorInstanceContext newConnectorInstanceContext)
-            throws ResourceException;
+    ConnectorInstanceContext enter(ConnectorInstanceContext newConnectorInstanceContext) throws ResourceException;
 
     void newTransaction() throws ResourceException;
 
-    void exit(ConnectorInstanceContext connectorInstanceContext)
-            throws ResourceException;
-
+    void exit(ConnectorInstanceContext connectorInstanceContext) throws ResourceException;
 }

Added: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/ConnectionExtension.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/ConnectionExtension.java?view=auto&rev=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/ConnectionExtension.java (added)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/ConnectionExtension.java Tue Jan  9 10:02:32 2007
@@ -0,0 +1,37 @@
+/**
+ *
+ * Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.geronimo.connector.mock;
+
+import javax.resource.cci.Connection;
+import javax.security.auth.Subject;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface ConnectionExtension extends Connection {
+    void error();
+
+    MockManagedConnection getManagedConnection();
+
+    Subject getSubject();
+
+    MockConnectionRequestInfo getConnectionRequestInfo();
+
+    boolean isClosed();
+
+    void reassociate(MockManagedConnection mockManagedConnection);
+}

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnection.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnection.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnection.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnection.java Tue Jan  9 10:02:32 2007
@@ -18,7 +18,6 @@
 package org.apache.geronimo.connector.mock;
 
 import javax.resource.ResourceException;
-import javax.resource.cci.Connection;
 import javax.resource.cci.ConnectionMetaData;
 import javax.resource.cci.Interaction;
 import javax.resource.cci.LocalTransaction;
@@ -31,7 +30,7 @@
  * @version $Rev$ $Date$
  *
  * */
-public class MockConnection implements Connection {
+public class MockConnection implements ConnectionExtension {
 
     private MockManagedConnection managedConnection;
     private Subject subject;

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnectionFactory.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnectionFactory.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnectionFactory.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/mock/MockConnectionFactory.java Tue Jan  9 10:02:32 2007
@@ -21,18 +21,14 @@
 import javax.naming.Reference;
 import javax.resource.ResourceException;
 import javax.resource.cci.Connection;
-import javax.resource.cci.ConnectionFactory;
 import javax.resource.cci.ConnectionSpec;
 import javax.resource.cci.RecordFactory;
 import javax.resource.cci.ResourceAdapterMetaData;
 import javax.resource.spi.ConnectionManager;
 
 /**
- *
- *
  * @version $Rev$ $Date$
- *
- * */
+ */
 public class MockConnectionFactory implements ConnectionFactoryExtension {
 
     private ConnectionManager connectionManager;
@@ -49,7 +45,7 @@
     }
 
     public Connection getConnection(ConnectionSpec properties) throws ResourceException {
-        return (MockConnection) connectionManager.allocateConnection(managedConnectionFactory, (MockConnectionRequestInfo) properties);
+        return (Connection) connectionManager.allocateConnection(managedConnectionFactory, (MockConnectionRequestInfo) properties);
     }
 
     public RecordFactory getRecordFactory() throws ResourceException {

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTest.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTest.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTest.java Tue Jan  9 10:02:32 2007
@@ -17,8 +17,8 @@
 
 package org.apache.geronimo.connector.outbound;
 
-import org.apache.geronimo.connector.mock.MockConnection;
 import org.apache.geronimo.connector.mock.MockXAResource;
+import org.apache.geronimo.connector.mock.ConnectionExtension;
 import org.apache.geronimo.connector.outbound.connectiontracking.DefaultInterceptor;
 import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContext;
 import org.apache.geronimo.transaction.GeronimoUserTransaction;
@@ -66,7 +66,7 @@
     public void testUserTransactionEnlistingExistingConnections() throws Throwable {
         mockComponent = new DefaultInterceptor() {
             public Object invoke(ConnectorInstanceContext newConnectorInstanceContext) throws Throwable {
-                MockConnection mockConnection = (MockConnection) connectionFactory.getConnection();
+                ConnectionExtension mockConnection = (ConnectionExtension) connectionFactory.getConnection();
                 mockManagedConnection = mockConnection.getManagedConnection();
                 userTransaction.begin();
                 MockXAResource mockXAResource = (MockXAResource) mockManagedConnection.getXAResource();
@@ -96,9 +96,9 @@
         unshareableResources.add(name);
         mockComponent = new DefaultInterceptor() {
             public Object invoke(ConnectorInstanceContext newConnectorInstanceContext) throws Throwable {
-                MockConnection mockConnection1 = (MockConnection) connectionFactory.getConnection();
+                ConnectionExtension mockConnection1 = (ConnectionExtension) connectionFactory.getConnection();
                 mockManagedConnection = mockConnection1.getManagedConnection();
-                MockConnection mockConnection2 = (MockConnection) connectionFactory.getConnection();
+                ConnectionExtension mockConnection2 = (ConnectionExtension) connectionFactory.getConnection();
                 //the 2 cx are for the same RM, so tm will call commit only one one (the first)
                 //mockManagedConnection = mockConnection2.getManagedConnection();
                 assertNotNull("Expected non-null managedconnection 1", mockConnection1.getManagedConnection());

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTestUtils.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTestUtils.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTestUtils.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionManagerTestUtils.java Tue Jan  9 10:02:32 2007
@@ -23,10 +23,10 @@
 import javax.transaction.TransactionManager;
 import javax.transaction.UserTransaction;
 
-import org.apache.geronimo.connector.mock.MockConnection;
 import org.apache.geronimo.connector.mock.MockConnectionFactory;
 import org.apache.geronimo.connector.mock.MockManagedConnection;
 import org.apache.geronimo.connector.mock.MockManagedConnectionFactory;
+import org.apache.geronimo.connector.mock.ConnectionExtension;
 import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PartitionedPool;
 import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport;
 import org.apache.geronimo.connector.outbound.connectionmanagerconfig.TransactionSupport;
@@ -80,7 +80,7 @@
 
     protected DefaultInterceptor mockComponent = new DefaultInterceptor() {
         public Object invoke(ConnectorInstanceContext newConnectorInstanceContext) throws Throwable {
-            MockConnection mockConnection = (MockConnection) connectionFactory.getConnection();
+            ConnectionExtension mockConnection = (ConnectionExtension) connectionFactory.getConnection();
             mockManagedConnection = mockConnection.getManagedConnection();
             mockConnection.close();
             return null;

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptorTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptorTest.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptorTest.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ConnectionTrackingInterceptorTest.java Tue Jan  9 10:02:32 2007
@@ -125,14 +125,16 @@
     //ConnectionTracker interface
     public void handleObtained(
             ConnectionTrackingInterceptor connectionTrackingInterceptor,
-            ConnectionInfo connectionInfo) {
+            ConnectionInfo connectionInfo, 
+            boolean reassociate) {
         obtainedConnectionTrackingInterceptor = connectionTrackingInterceptor;
         obtainedTrackedConnectionInfo = connectionInfo;
     }
 
     public void handleReleased(
             ConnectionTrackingInterceptor connectionTrackingInterceptor,
-            ConnectionInfo connectionInfo) {
+            ConnectionInfo connectionInfo, 
+            ConnectionReturnAction connectionReturnAction) {
         releasedConnectionTrackingInterceptor = connectionTrackingInterceptor;
         releasedTrackedConnectionInfo = connectionInfo;
     }

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ManagedConnectionFactoryWrapperTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ManagedConnectionFactoryWrapperTest.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ManagedConnectionFactoryWrapperTest.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/ManagedConnectionFactoryWrapperTest.java Tue Jan  9 10:02:32 2007
@@ -155,11 +155,13 @@
 
     public static class MockConnectionTrackingCoordinator implements ConnectionTracker {
         public void handleObtained(ConnectionTrackingInterceptor connectionTrackingInterceptor,
-                                   ConnectionInfo connectionInfo) {
+                                   ConnectionInfo connectionInfo,
+                                   boolean reassociate) {
         }
 
         public void handleReleased(ConnectionTrackingInterceptor connectionTrackingInterceptor,
-                                   ConnectionInfo connectionInfo) {
+                                   ConnectionInfo connectionInfo,
+                                   ConnectionReturnAction connectionReturnAction) {
         }
 
         public void setEnvironment(ConnectionInfo connectionInfo, String key) {

Added: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorProxyTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorProxyTest.java?view=auto&rev=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorProxyTest.java (added)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorProxyTest.java Tue Jan  9 10:02:32 2007
@@ -0,0 +1,375 @@
+/**
+ *
+ * Copyright 2006 The Apache Software Foundation
+ *
+ *  Licensed 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.geronimo.connector.outbound.connectiontracking;
+
+import junit.framework.TestCase;
+import org.apache.geronimo.connector.outbound.ConnectionInterceptor;
+import org.apache.geronimo.connector.outbound.ConnectionTrackingInterceptor;
+import org.apache.geronimo.connector.outbound.ConnectionInfo;
+import org.apache.geronimo.connector.outbound.ConnectionReturnAction;
+import org.apache.geronimo.connector.outbound.ManagedConnectionInfo;
+import org.apache.geronimo.connector.outbound.GeronimoConnectionEventListener;
+
+import javax.security.auth.Subject;
+import javax.resource.ResourceException;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.DissociatableManagedConnection;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ConnectionEventListener;
+import javax.resource.spi.LocalTransaction;
+import javax.resource.spi.ManagedConnectionMetaData;
+import javax.transaction.xa.XAResource;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.lang.reflect.Proxy;
+import java.io.PrintWriter;
+
+/**
+ * @version $Rev: 476049 $ $Date: 2006-11-16 20:35:17 -0800 (Thu, 16 Nov 2006) $
+ */
+public class ConnectionTrackingCoordinatorProxyTest extends TestCase implements ConnectionInterceptor {
+    private static final String name1 = "foo";
+    private ConnectionTrackingCoordinator connectionTrackingCoordinator;
+    private ConnectionTrackingInterceptor key1;
+    private Subject subject = null;
+    private Set unshareableResources;
+    private Set applicationManagedSecurityResources;
+    private ManagedConnectionInfo mci;
+    private ConnectionImpl connection;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        connectionTrackingCoordinator = new ConnectionTrackingCoordinator(true);
+        key1 = new ConnectionTrackingInterceptor(this, name1, connectionTrackingCoordinator);
+        unshareableResources = new HashSet();
+        applicationManagedSecurityResources = new HashSet();
+
+        mci = new ManagedConnectionInfo(null, null);
+        mci.setManagedConnection(new MockManagedConnection());
+        mci.setConnectionEventListener(new GeronimoConnectionEventListener(this, mci));
+        connection = new ConnectionImpl("ConnectionString");
+    }
+
+    protected void tearDown() throws Exception {
+        connectionTrackingCoordinator = null;
+        key1 = null;
+        super.tearDown();
+    }
+
+    public void testSimpleComponentContextLifecyle() throws Exception {
+        // enter component context
+        ConnectorInstanceContextImpl componentContext = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
+        ConnectorInstanceContext oldConnectorInstanceContext = connectionTrackingCoordinator.enter(componentContext);
+        assertNull("Expected old instance context to be null", oldConnectorInstanceContext);
+
+        // simulate create connection
+        ConnectionInfo connectionInfo = createConnectionInfo();
+        connectionTrackingCoordinator.handleObtained(key1, connectionInfo, false);
+
+        // connection should be in component instance context
+        Map connectionManagerMap = componentContext.getConnectionManagerMap();
+        Set infos = (Set) connectionManagerMap.get(key1);
+        assertNotNull("Expected one connections for key1", infos);
+        assertEquals("Expected one connection for key1", 1, infos.size());
+        assertTrue("Expected to get supplied ConnectionInfo from infos", connectionInfo == infos.iterator().next());
+
+        // verify handle
+        Object handle = connectionInfo.getConnectionHandle();
+        assertNotNull("Expected a handle from ConnectionInfo", handle);
+        assertTrue("Expected handle to be an instance of ConnectionImpl", handle instanceof ConnectionImpl);
+        ConnectionImpl connection = (ConnectionImpl) handle;
+        assertEquals("connection.getString()", "ConnectionString", connection.getString());
+
+        // verify proxy
+        Object proxy = connectionInfo.getConnectionProxy();
+        assertNotNull("Expected a proxy from ConnectionInfo", proxy);
+        assertTrue("Expected proxy to be an instance of Connection", proxy instanceof Connection);
+        Connection connectionProxy = (Connection) proxy;
+        assertEquals("connection.getString()", "ConnectionString", connectionProxy.getString());
+        assertSame("Expected connection.getUnmanaged() to be connectionImpl", connection, connectionProxy.getUnmanaged());
+        assertNotSame("Expected connection be proxied", connection, connectionProxy);
+
+        // exit component context
+        connectionTrackingCoordinator.exit(oldConnectorInstanceContext);
+
+        // connection should not be in context
+        connectionManagerMap = componentContext.getConnectionManagerMap();
+        infos = (Set) connectionManagerMap.get(key1);
+        assertEquals("Expected no connection set for key1", null, infos);
+
+        // enter again, and close the handle
+        oldConnectorInstanceContext = connectionTrackingCoordinator.enter(componentContext);
+        assertNull("Expected old instance context to be null", oldConnectorInstanceContext);
+        connectionTrackingCoordinator.handleReleased(key1, connectionInfo, ConnectionReturnAction.DESTROY);
+        connectionTrackingCoordinator.exit(oldConnectorInstanceContext);
+
+        // verify proxy is invalid
+        try {
+            connectionProxy.getString();
+            fail("Connection was destroyed so proxy should throw an IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    public void testReassociateConnection() throws Exception {
+        // enter component context
+        ConnectorInstanceContextImpl componentContext = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
+        ConnectorInstanceContext oldConnectorInstanceContext1 = connectionTrackingCoordinator.enter(componentContext);
+        assertNull("Expected old component context to be null", oldConnectorInstanceContext1);
+
+        // simulate create connection
+        ConnectionInfo connectionInfo = createConnectionInfo();
+        connectionTrackingCoordinator.handleObtained(key1, connectionInfo, false);
+
+        // connection should be in component instance context
+        Map connectionManagerMap = componentContext.getConnectionManagerMap();
+        Set infos = (Set) connectionManagerMap.get(key1);
+        assertNotNull("Expected one connections for key1", infos);
+        assertEquals("Expected one connection for key1", 1, infos.size());
+        assertTrue("Expected to get supplied ConnectionInfo from infos", connectionInfo == infos.iterator().next());
+
+        // verify handle
+        Object handle = connectionInfo.getConnectionHandle();
+        assertNotNull("Expected a handle from ConnectionInfo", handle);
+        assertTrue("Expected handle to be an instance of ConnectionImpl", handle instanceof ConnectionImpl);
+        ConnectionImpl connection = (ConnectionImpl) handle;
+        assertEquals("connection.getString()", "ConnectionString", connection.getString());
+
+        // verify proxy
+        Object proxy = connectionInfo.getConnectionProxy();
+        assertNotNull("Expected a proxy from ConnectionInfo", proxy);
+        assertTrue("Expected proxy to be an instance of Connection", proxy instanceof Connection);
+        Connection connectionProxy = (Connection) proxy;
+        assertEquals("connection.getString()", "ConnectionString", connectionProxy.getString());
+        assertSame("Expected connection.getUnmanaged() to be connectionImpl", connection, connectionProxy.getUnmanaged());
+        assertNotSame("Expected connection be proxied", connection, connectionProxy);
+
+
+        // exit outer component context
+        connectionTrackingCoordinator.exit(oldConnectorInstanceContext1);
+
+        // proxy should be disconnected
+        ConnectionTrackingCoordinator.ConnectionInvocationHandler invocationHandler = (ConnectionTrackingCoordinator.ConnectionInvocationHandler) Proxy.getInvocationHandler(connectionProxy);
+        assertTrue("Proxy should be disconnected", invocationHandler.isReleased());
+
+        // enter again
+        oldConnectorInstanceContext1 = connectionTrackingCoordinator.enter(componentContext);
+        assertNull("Expected old component context to be null", oldConnectorInstanceContext1);
+
+        // use connection to cause it to get a new handle
+        assertEquals("connection.getString()", "ConnectionString", connectionProxy.getString());
+        assertSame("Expected connection.getUnmanaged() to be original connection", connection, connection.getUnmanaged());
+        assertNotSame("Expected connection to not be original connection", connection, connectionProxy);
+
+        // destroy handle and exit context
+        connectionTrackingCoordinator.handleReleased(key1, connectionInfo, ConnectionReturnAction.DESTROY);
+        connectionTrackingCoordinator.exit(oldConnectorInstanceContext1);
+
+        // connection should not be in context
+        connectionManagerMap = componentContext.getConnectionManagerMap();
+        infos = (Set) connectionManagerMap.get(key1);
+        assertNull("Expected no connection set for key1", infos);
+
+        // verify proxy is invalid
+        try {
+            connectionProxy.getString();
+            fail("Connection was destroyed so proxy should throw an IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    // some code calls the release method using a freshly constructed ContainerInfo without a proxy
+    // the ConnectionTrackingCoordinator must find the correct proxy and call releaseHandle or destroy
+    public void testReleaseNoProxy() throws Exception {
+        // enter component context
+        ConnectorInstanceContextImpl componentContext = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
+        ConnectorInstanceContext oldConnectorInstanceContext1 = connectionTrackingCoordinator.enter(componentContext);
+        assertNull("Expected old component context to be null", oldConnectorInstanceContext1);
+
+        // simulate create connection
+        ConnectionInfo connectionInfo = createConnectionInfo();
+        connectionTrackingCoordinator.handleObtained(key1, connectionInfo, false);
+
+        // connection should be in component instance context
+        Map connectionManagerMap = componentContext.getConnectionManagerMap();
+        Set infos = (Set) connectionManagerMap.get(key1);
+        assertNotNull("Expected one connections for key1", infos);
+        assertEquals("Expected one connection for key1", 1, infos.size());
+        assertTrue("Expected to get supplied ConnectionInfo from infos", connectionInfo == infos.iterator().next());
+
+        // verify handle
+        Object handle = connectionInfo.getConnectionHandle();
+        assertNotNull("Expected a handle from ConnectionInfo", handle);
+        assertTrue("Expected handle to be an instance of ConnectionImpl", handle instanceof ConnectionImpl);
+        ConnectionImpl connection = (ConnectionImpl) handle;
+        assertEquals("connection.getString()", "ConnectionString", connection.getString());
+
+        // verify proxy
+        Object proxy = connectionInfo.getConnectionProxy();
+        assertNotNull("Expected a proxy from ConnectionInfo", proxy);
+        assertTrue("Expected proxy to be an instance of Connection", proxy instanceof Connection);
+        Connection connectionProxy = (Connection) proxy;
+        assertEquals("connection.getString()", "ConnectionString", connectionProxy.getString());
+        assertSame("Expected connection.getUnmanaged() to be connectionImpl", connection, connectionProxy.getUnmanaged());
+        assertNotSame("Expected connection be proxied", connection, connectionProxy);
+
+
+        // simulate handle release due to a event listener, which won't hav the proxy
+        connectionTrackingCoordinator.handleReleased(key1, createConnectionInfo(), ConnectionReturnAction.RETURN_HANDLE);
+
+        // proxy should be disconnected
+        ConnectionTrackingCoordinator.ConnectionInvocationHandler invocationHandler = (ConnectionTrackingCoordinator.ConnectionInvocationHandler) Proxy.getInvocationHandler(connectionProxy);
+        assertTrue("Proxy should be disconnected", invocationHandler.isReleased());
+
+        // use connection to cause it to get a new handle
+        assertEquals("connection.getString()", "ConnectionString", connectionProxy.getString());
+        assertFalse("Proxy should be connected", invocationHandler.isReleased());
+        assertSame("Expected connection.getUnmanaged() to be original connection", connection, connection.getUnmanaged());
+        assertNotSame("Expected connection to not be original connection", connection, connectionProxy);
+
+        // exit outer component context
+        connectionTrackingCoordinator.exit(oldConnectorInstanceContext1);
+
+        // proxy should be disconnected
+        assertTrue("Proxy should be disconnected", invocationHandler.isReleased());
+
+        // enter again
+        oldConnectorInstanceContext1 = connectionTrackingCoordinator.enter(componentContext);
+        assertNull("Expected old component context to be null", oldConnectorInstanceContext1);
+
+        // use connection to cause it to get a new handle
+        assertEquals("connection.getString()", "ConnectionString", connectionProxy.getString());
+        assertSame("Expected connection.getUnmanaged() to be original connection", connection, connection.getUnmanaged());
+        assertNotSame("Expected connection to not be original connection", connection, connectionProxy);
+
+        // simulate handle destroy due to a event listener, which won't hav the proxy
+        connectionTrackingCoordinator.handleReleased(key1, createConnectionInfo(), ConnectionReturnAction.DESTROY);
+
+        // verify proxy is invalid
+        try {
+            connectionProxy.getString();
+            fail("Connection was destroyed so proxy should throw an IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+
+        // exit context
+        connectionTrackingCoordinator.exit(oldConnectorInstanceContext1);
+
+        // connection should not be in context
+        connectionManagerMap = componentContext.getConnectionManagerMap();
+        infos = (Set) connectionManagerMap.get(key1);
+        assertNull("Expected no connection set for key1", infos);
+
+        // verify proxy is invalid
+        try {
+            connectionProxy.getString();
+            fail("Connection was destroyed so proxy should throw an IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+
+    public Subject mapSubject(Subject sourceSubject) {
+        return subject;
+    }
+
+    public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
+    }
+
+    public void returnConnection(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction) {
+    }
+
+    public void destroy() {
+    }
+
+    private ConnectionInfo createConnectionInfo() {
+        ConnectionInfo ci = new ConnectionInfo(mci);
+        ci.setConnectionHandle(connection);
+        mci.addConnectionHandle(ci);
+        return ci;
+    }
+
+
+    public static interface Connection {
+        String getString();
+        Connection getUnmanaged();
+    }
+
+    public static class ConnectionImpl implements Connection {
+        private final String string;
+
+        public ConnectionImpl(String string) {
+            this.string = string;
+        }
+
+        public String getString() {
+            return string;
+        }
+
+        public Connection getUnmanaged() {
+            return this;
+        }
+    }
+
+    public static class MockManagedConnection implements ManagedConnection, DissociatableManagedConnection {
+           public Object getConnection(Subject defaultSubject, ConnectionRequestInfo connectionRequestInfo) throws ResourceException {
+               return null;
+           }
+
+           public void destroy() throws ResourceException {
+           }
+
+           public void cleanup() throws ResourceException {
+           }
+
+           public void associateConnection(Object object) throws ResourceException {
+           }
+
+           public void addConnectionEventListener(ConnectionEventListener connectionEventListener) {
+           }
+
+           public void removeConnectionEventListener(ConnectionEventListener connectionEventListener) {
+           }
+
+           public XAResource getXAResource() throws ResourceException {
+               return null;
+           }
+
+           public LocalTransaction getLocalTransaction() throws ResourceException {
+               return null;
+           }
+
+           public ManagedConnectionMetaData getMetaData() throws ResourceException {
+               return null;
+           }
+
+           public void setLogWriter(PrintWriter printWriter) throws ResourceException {
+           }
+
+           public PrintWriter getLogWriter() throws ResourceException {
+               return null;
+           }
+
+           public void dissociateConnections() throws ResourceException {
+           }
+       }
+}

Modified: geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorTest.java
URL: http://svn.apache.org/viewvc/geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorTest.java?view=diff&rev=494504&r1=494503&r2=494504
==============================================================================
--- geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorTest.java (original)
+++ geronimo/server/branches/1.2/modules/geronimo-connector/src/test/java/org/apache/geronimo/connector/outbound/connectiontracking/ConnectionTrackingCoordinatorTest.java Tue Jan  9 10:02:32 2007
@@ -31,15 +31,10 @@
 import org.apache.geronimo.connector.outbound.ConnectionTrackingInterceptor;
 import org.apache.geronimo.connector.outbound.ManagedConnectionInfo;
 import org.apache.geronimo.connector.outbound.GeronimoConnectionEventListener;
-import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContextImpl;
-import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContext;
 
 /**
- *
- *
  * @version $Rev$ $Date$
- *
- * */
+ */
 public class ConnectionTrackingCoordinatorTest extends TestCase
         implements ConnectionInterceptor {
 
@@ -47,15 +42,16 @@
     private static final String name2 = "bar";
     private ConnectionTrackingCoordinator connectionTrackingCoordinator;
     private ConnectionTrackingInterceptor key1;
-    private ConnectionTrackingInterceptor key2;
+    private ConnectionTrackingInterceptor nestedKey;
     private Subject subject = null;
     private Set unshareableResources;
     private Set applicationManagedSecurityResources;
 
     protected void setUp() throws Exception {
-        connectionTrackingCoordinator = new ConnectionTrackingCoordinator();
+        super.setUp();
+        connectionTrackingCoordinator = new ConnectionTrackingCoordinator(false);
         key1 = new ConnectionTrackingInterceptor(this, name1, connectionTrackingCoordinator);
-        key2 = new ConnectionTrackingInterceptor(this, name2, connectionTrackingCoordinator);
+        nestedKey = new ConnectionTrackingInterceptor(this, name2, connectionTrackingCoordinator);
         unshareableResources = new HashSet();
         applicationManagedSecurityResources = new HashSet();
     }
@@ -63,27 +59,37 @@
     protected void tearDown() throws Exception {
         connectionTrackingCoordinator = null;
         key1 = null;
-        key2 = null;
+        nestedKey = null;
+        super.tearDown();
     }
 
     public void testSimpleComponentContextLifecyle() throws Exception {
+        // enter component context
         ConnectorInstanceContextImpl componentContext = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
         ConnectorInstanceContext oldConnectorInstanceContext = connectionTrackingCoordinator.enter(componentContext);
         assertNull("Expected old instance context to be null", oldConnectorInstanceContext);
-        //give the context a ConnectionInfo
+
+        // simulate create connection
         ConnectionInfo connectionInfo = newConnectionInfo();
-        connectionTrackingCoordinator.handleObtained(key1, connectionInfo);
+        connectionTrackingCoordinator.handleObtained(key1, connectionInfo, false);
+
+        // exit component context
         connectionTrackingCoordinator.exit(oldConnectorInstanceContext);
+
+        // connection should be in component instance context
         Map connectionManagerMap = componentContext.getConnectionManagerMap();
         Set infos = (Set) connectionManagerMap.get(key1);
+        assertNotNull("Expected one connections for key1", infos);
         assertEquals("Expected one connection for key1", 1, infos.size());
         assertTrue("Expected to get supplied ConnectionInfo from infos", connectionInfo == infos.iterator().next());
 
-        //Enter again, and close the handle
+        // enter again, and close the handle
         oldConnectorInstanceContext = connectionTrackingCoordinator.enter(componentContext);
         assertNull("Expected old instance context to be null", oldConnectorInstanceContext);
-        connectionTrackingCoordinator.handleReleased(key1, connectionInfo);
+        connectionTrackingCoordinator.handleReleased(key1, connectionInfo, ConnectionReturnAction.DESTROY);
         connectionTrackingCoordinator.exit(oldConnectorInstanceContext);
+
+        // connection should not be in context
         connectionManagerMap = componentContext.getConnectionManagerMap();
         infos = (Set) connectionManagerMap.get(key1);
         assertEquals("Expected no connection set for key1", null, infos);
@@ -99,44 +105,53 @@
     }
 
     public void testNestedComponentContextLifecyle() throws Exception {
+        // enter component context
         ConnectorInstanceContextImpl componentContext1 = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
         ConnectorInstanceContext oldConnectorInstanceContext1 = connectionTrackingCoordinator.enter(componentContext1);
         assertNull("Expected old component context to be null", oldConnectorInstanceContext1);
-        //give the context a ConnectionInfo
+
+        // simulate create connection
         ConnectionInfo connectionInfo1 = newConnectionInfo();
-        connectionTrackingCoordinator.handleObtained(key1, connectionInfo1);
+        connectionTrackingCoordinator.handleObtained(key1, connectionInfo1, false);
 
-        //Simulate calling another component
-        ConnectorInstanceContextImpl componentContext2 = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
-        ConnectorInstanceContext oldConnectorInstanceContext2 = connectionTrackingCoordinator.enter(componentContext2);
+        // enter another (nested) component context
+        ConnectorInstanceContextImpl nextedComponentContext = new ConnectorInstanceContextImpl(unshareableResources, applicationManagedSecurityResources);
+        ConnectorInstanceContext oldConnectorInstanceContext2 = connectionTrackingCoordinator.enter(nextedComponentContext);
         assertTrue("Expected returned component context to be componentContext1", oldConnectorInstanceContext2 == componentContext1);
-        //give the context a ConnectionInfo
-        ConnectionInfo connectionInfo2 = newConnectionInfo();
-        connectionTrackingCoordinator.handleObtained(key2, connectionInfo2);
 
+        // simulate create connection in nested context
+        ConnectionInfo nestedConnectionInfo = newConnectionInfo();
+        connectionTrackingCoordinator.handleObtained(nestedKey, nestedConnectionInfo, false);
+
+        // exit nested component context
         connectionTrackingCoordinator.exit(oldConnectorInstanceContext2);
-        Map connectionManagerMap2 = componentContext2.getConnectionManagerMap();
-        Set infos2 = (Set) connectionManagerMap2.get(key2);
-        assertEquals("Expected one connection for key2", 1, infos2.size());
-        assertTrue("Expected to get supplied ConnectionInfo from infos", connectionInfo2 == infos2.iterator().next());
-        assertEquals("Expected no connection for key1", null, connectionManagerMap2.get(key1));
+        Map nestedConnectionManagerMap = nextedComponentContext.getConnectionManagerMap();
+        Set nestedInfos = (Set) nestedConnectionManagerMap.get(nestedKey);
+        assertNotNull("Expected one connections for key2", nestedInfos);
+        assertEquals("Expected one connection for key2", 1, nestedInfos.size());
+        assertSame("Expected to get supplied ConnectionInfo from infos", nestedConnectionInfo, nestedInfos.iterator().next());
+        assertNull("Expected no connection for key1", nestedConnectionManagerMap.get(key1));
 
 
+        // exit outer component context
         connectionTrackingCoordinator.exit(oldConnectorInstanceContext1);
-        Map connectionManagerMap1 = componentContext1.getConnectionManagerMap();
-        Set infos1 = (Set) connectionManagerMap1.get(key1);
+        Map connectionManagerMap = componentContext1.getConnectionManagerMap();
+        Set infos1 = (Set) connectionManagerMap.get(key1);
+        assertNotNull("Expected one connections for key1", infos1);
         assertEquals("Expected one connection for key1", 1, infos1.size());
-        assertTrue("Expected to get supplied ConnectionInfo from infos", connectionInfo1 == infos1.iterator().next());
-        assertEquals("Expected no connection for key2", null, connectionManagerMap1.get(key2));
+        assertSame("Expected to get supplied ConnectionInfo from infos", connectionInfo1, infos1.iterator().next());
+        assertNull("Expected no connection for key2", connectionManagerMap.get(nestedKey));
 
-        //Enter again, and close the handle
+        // enter again, and close the handle
         oldConnectorInstanceContext1 = connectionTrackingCoordinator.enter(componentContext1);
         assertNull("Expected old component context to be null", oldConnectorInstanceContext1);
-        connectionTrackingCoordinator.handleReleased(key1, connectionInfo1);
+        connectionTrackingCoordinator.handleReleased(key1, connectionInfo1, ConnectionReturnAction.DESTROY);
         connectionTrackingCoordinator.exit(oldConnectorInstanceContext1);
-        connectionManagerMap1 = componentContext1.getConnectionManagerMap();
-        infos1 = (Set) connectionManagerMap1.get(key1);
-        assertEquals("Expected no connection set for key1", null, infos1);
+
+        // connection should not be in context
+        connectionManagerMap = componentContext1.getConnectionManagerMap();
+        infos1 = (Set) connectionManagerMap.get(key1);
+        assertNull("Expected no connection set for key1", infos1);
     }
 
     public Subject mapSubject(Subject sourceSubject) {
@@ -148,6 +163,7 @@
 
     public void returnConnection(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction) {
     }
+
     public void destroy() {        
     }
 }



Mime
View raw message