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: 620123 $ $Date: 2008-02-09 09:14:26 -0500 (Sat, 09 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 }