001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.connector.outbound;
019    
020    import java.util.Collection;
021    import java.util.Iterator;
022    
023    import javax.resource.ResourceException;
024    import javax.resource.spi.DissociatableManagedConnection;
025    import javax.resource.spi.ManagedConnection;
026    
027    import org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTracker;
028    
029    /**
030     * ConnectionTrackingInterceptor.java handles communication with the
031     * CachedConnectionManager.  On method call entry, cached handles are
032     * checked for the correct Subject.  On method call exit, cached
033     * handles are disassociated if possible. On getting or releasing
034     * a connection the CachedConnectionManager is notified.
035     *
036     *
037     * @version $Rev: 585608 $ $Date: 2007-10-17 19:56:54 +0200 (Wed, 17 Oct 2007) $
038     */
039    public class ConnectionTrackingInterceptor implements ConnectionInterceptor {
040    
041        private final ConnectionInterceptor next;
042        private final String key;
043        private final ConnectionTracker connectionTracker;
044    
045        public ConnectionTrackingInterceptor(
046                final ConnectionInterceptor next,
047                final String key,
048                final ConnectionTracker connectionTracker
049                ) {
050            this.next = next;
051            this.key = key;
052            this.connectionTracker = connectionTracker;
053        }
054    
055        /**
056         * called by: GenericConnectionManager.allocateConnection, GenericConnectionManager.associateConnection, and enter.
057         * in: connectionInfo is non-null, and has non-null ManagedConnectionInfo with non-null managedConnectionfactory.
058         * connection handle may or may not be null.
059         * out: connectionInfo has non-null connection handle, non null ManagedConnectionInfo with non-null ManagedConnection and GeronimoConnectionEventListener.
060         * connection tracker has been notified of handle-managed connection association.
061         * @param connectionInfo
062         * @throws ResourceException
063         */
064        public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
065            connectionTracker.setEnvironment(connectionInfo, key);
066            next.getConnection(connectionInfo);
067            connectionTracker.handleObtained(this, connectionInfo, false);
068        }
069    
070        /**
071         * Called when a proxied connection which has been released need to be reassociated with a real connection.
072         */
073        public void reassociateConnection(ConnectionInfo connectionInfo) throws ResourceException {
074            connectionTracker.setEnvironment(connectionInfo, key);
075            next.getConnection(connectionInfo);
076            connectionTracker.handleObtained(this, connectionInfo, true);
077        }
078    
079        /**
080         * called by: GeronimoConnectionEventListener.connectionClosed, GeronimoConnectionEventListener.connectionErrorOccurred, exit
081         * in: handle has already been dissociated from ManagedConnection. connectionInfo not null, has non-null ManagedConnectionInfo, ManagedConnectionInfo has non-null ManagedConnection
082         * handle can be null if called from error in ManagedConnection in pool.
083         * out: connectionTracker has been notified, ManagedConnectionInfo null.
084         * @param connectionInfo
085         * @param connectionReturnAction
086         */
087        public void returnConnection(
088                ConnectionInfo connectionInfo,
089                ConnectionReturnAction connectionReturnAction) {
090            connectionTracker.handleReleased(this, connectionInfo, connectionReturnAction);
091            next.returnConnection(connectionInfo, connectionReturnAction);
092        }
093    
094        public void destroy() {
095            next.destroy();
096        }
097        
098        public void enter(Collection<ConnectionInfo> connectionInfos) throws ResourceException {
099            for (ConnectionInfo connectionInfo : connectionInfos) {
100                next.getConnection(connectionInfo);
101            }
102    
103        }
104    
105        public void exit(Collection<ConnectionInfo> connectionInfos)
106                throws ResourceException {
107            for (Iterator<ConnectionInfo> iterator = connectionInfos.iterator(); iterator.hasNext();) {
108                ConnectionInfo connectionInfo = iterator.next();
109                if (connectionInfo.isUnshareable()) {
110                    //if one is, they all are
111                    return;
112                }
113                ManagedConnectionInfo managedConnectionInfo = connectionInfo.getManagedConnectionInfo();
114                ManagedConnection managedConnection = managedConnectionInfo.getManagedConnection();
115                if (managedConnection instanceof DissociatableManagedConnection
116                        && managedConnectionInfo.isFirstConnectionInfo(connectionInfo)) {
117                    iterator.remove();
118                    ((DissociatableManagedConnection) managedConnection).dissociateConnections();
119                    managedConnectionInfo.clearConnectionHandles();
120                    //todo this needs some kind of check so cx isn't returned more than once
121                    //in case dissociate calls connection closed event and returns cx to pool.
122                    returnConnection(connectionInfo, ConnectionReturnAction.RETURN_HANDLE);
123                }
124            }
125        }
126    }