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.IdentityHashMap;
021    import java.util.Iterator;
022    import java.util.List;
023    import java.util.Map;
024    import java.util.ArrayList;
025    
026    import javax.resource.ResourceException;
027    import javax.resource.spi.ManagedConnection;
028    import javax.resource.spi.ManagedConnectionFactory;
029    
030    /**
031     * This pool is the most spec-compliant pool.  It can be used by itself with no partitioning.
032     * It is apt to be the slowest pool.
033     * For each connection request, it synchronizes access to the pool and asks the
034     * ManagedConnectionFactory for a match from among all managed connections.  If none is found,
035     * it may discard a random existing connection, and creates a new connection.
036     *
037     * @version $Rev: 620213 $ $Date: 2008-02-10 00:13:09 +0100 (Sun, 10 Feb 2008) $
038     */
039    public class SinglePoolMatchAllConnectionInterceptor extends AbstractSinglePoolConnectionInterceptor {
040    
041        private final Map<ManagedConnection, ManagedConnectionInfo> pool;
042    
043        public SinglePoolMatchAllConnectionInterceptor(final ConnectionInterceptor next,
044                                                       int maxSize,
045                                                       int minSize,
046                                                       int blockingTimeoutMilliseconds,
047                                                       int idleTimeoutMinutes) {
048    
049            super(next, maxSize, minSize, blockingTimeoutMilliseconds, idleTimeoutMinutes);
050            pool = new IdentityHashMap<ManagedConnection, ManagedConnectionInfo>(maxSize);
051        }
052    
053        protected void internalGetConnection(ConnectionInfo connectionInfo) throws ResourceException {
054            synchronized (pool) {
055                if (destroyed) {
056                    throw new ResourceException("ManagedConnection pool has been destroyed");
057                }
058                if (!pool.isEmpty()) {
059                    ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
060                    ManagedConnectionFactory managedConnectionFactory = mci.getManagedConnectionFactory();
061                    ManagedConnection matchedMC =
062                            managedConnectionFactory
063                                    .matchManagedConnections(pool.keySet(),
064                                            mci.getSubject(),
065                                            mci.getConnectionRequestInfo());
066                    if (matchedMC != null) {
067                        connectionInfo.setManagedConnectionInfo(pool.get(matchedMC));
068                        pool.remove(matchedMC);
069                        if (log.isTraceEnabled()) {
070                            log.trace("Returning pooled connection " + connectionInfo.getManagedConnectionInfo());
071                        }
072                        if (connectionCount < minSize) {
073                            timer.schedule(new FillTask(connectionInfo), 10);
074                        }
075                        return;
076                    }
077                }
078                //matching failed or pool is empty
079                //if pool is at maximum size, pick a cx to kill
080                if (connectionCount == maxSize) {
081                    Iterator iterator = pool.entrySet().iterator();
082                    ManagedConnectionInfo kill = (ManagedConnectionInfo) ((Map.Entry) iterator.next()).getValue();
083                    iterator.remove();
084                    ConnectionInfo killInfo = new ConnectionInfo(kill);
085                    internalReturn(killInfo, ConnectionReturnAction.DESTROY);
086                }
087                next.getConnection(connectionInfo);
088                connectionCount++;
089                if (log.isTraceEnabled()) {
090                    log.trace("Returning new connection " + connectionInfo.getManagedConnectionInfo());
091                }
092                if (connectionCount < minSize) {
093                    timer.schedule(new FillTask(connectionInfo), 10);
094                }
095    
096            }
097        }
098    
099        protected void doAdd(ManagedConnectionInfo mci) {
100            pool.put(mci.getManagedConnection(), mci);
101        }
102    
103        protected Object getPool() {
104            return pool;
105        }
106    
107        protected boolean doRemove(ManagedConnectionInfo mci) {
108            return pool.remove(mci.getManagedConnection()) == null;
109        }
110    
111        protected void internalDestroy() {
112            synchronized (pool) {
113                for (ManagedConnection managedConnection : pool.keySet()) {
114                    try {
115                        managedConnection.destroy();
116                    } catch (ResourceException ignore) {
117                    }
118                }
119                pool.clear();
120            }
121        }
122    
123        public int getIdleConnectionCount() {
124            synchronized (pool) {
125                return pool.size();
126            }
127        }
128    
129        protected void transferConnections(int maxSize, int shrinkNow) {
130            List<ConnectionInfo> killList = new ArrayList<ConnectionInfo>(shrinkNow);
131            Iterator<Map.Entry<ManagedConnection, ManagedConnectionInfo>> it = pool.entrySet().iterator();
132            for (int i = 0; i < shrinkNow; i++) {
133                killList.add(new ConnectionInfo(it.next().getValue()));
134            }
135            for (ConnectionInfo killInfo: killList) {
136                internalReturn(killInfo, ConnectionReturnAction.DESTROY);
137            }
138        }
139    
140        protected void getExpiredManagedConnectionInfos(long threshold, List<ManagedConnectionInfo> killList) {
141            synchronized (pool) {
142                for (ManagedConnectionInfo mci : pool.values()) {
143                    if (mci.getLastUsed() < threshold) {
144                        killList.add(mci);
145                    }
146                }
147            }
148    
149        }
150    
151    }