| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.geronimo.connector.outbound; |
| |
| import java.util.IdentityHashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.ArrayList; |
| |
| import javax.resource.ResourceException; |
| import javax.resource.spi.ManagedConnection; |
| import javax.resource.spi.ManagedConnectionFactory; |
| |
| /** |
| * This pool is the most spec-compliant pool. It can be used by itself with no partitioning. |
| * It is apt to be the slowest pool. |
| * For each connection request, it synchronizes access to the pool and asks the |
| * ManagedConnectionFactory for a match from among all managed connections. If none is found, |
| * it may discard a random existing connection, and creates a new connection. |
| * |
| * @version $Rev$ $Date$ |
| */ |
| public class SinglePoolMatchAllConnectionInterceptor extends AbstractSinglePoolConnectionInterceptor { |
| |
| private final Map<ManagedConnection, ManagedConnectionInfo> pool; |
| |
| public SinglePoolMatchAllConnectionInterceptor(final ConnectionInterceptor next, |
| int maxSize, |
| int minSize, |
| int blockingTimeoutMilliseconds, |
| int idleTimeoutMinutes) { |
| |
| super(next, maxSize, minSize, blockingTimeoutMilliseconds, idleTimeoutMinutes); |
| pool = new IdentityHashMap<ManagedConnection, ManagedConnectionInfo>(maxSize); |
| } |
| |
| protected void internalGetConnection(ConnectionInfo connectionInfo) throws ResourceException { |
| synchronized (pool) { |
| if (destroyed) { |
| throw new ResourceException("ManagedConnection pool has been destroyed"); |
| } |
| if (!pool.isEmpty()) { |
| ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo(); |
| ManagedConnectionFactory managedConnectionFactory = mci.getManagedConnectionFactory(); |
| ManagedConnection matchedMC = |
| managedConnectionFactory |
| .matchManagedConnections(pool.keySet(), |
| mci.getSubject(), |
| mci.getConnectionRequestInfo()); |
| if (matchedMC != null) { |
| connectionInfo.setManagedConnectionInfo(pool.get(matchedMC)); |
| pool.remove(matchedMC); |
| if (log.isTraceEnabled()) { |
| log.trace("Returning pooled connection " + connectionInfo.getManagedConnectionInfo()); |
| } |
| if (connectionCount < minSize) { |
| timer.schedule(new FillTask(connectionInfo), 10); |
| } |
| return; |
| } |
| } |
| //matching failed or pool is empty |
| //if pool is at maximum size, pick a cx to kill |
| if (connectionCount == maxSize) { |
| Iterator iterator = pool.entrySet().iterator(); |
| ManagedConnectionInfo kill = (ManagedConnectionInfo) ((Map.Entry) iterator.next()).getValue(); |
| iterator.remove(); |
| ConnectionInfo killInfo = new ConnectionInfo(kill); |
| internalReturn(killInfo, ConnectionReturnAction.DESTROY); |
| } |
| next.getConnection(connectionInfo); |
| connectionCount++; |
| if (log.isTraceEnabled()) { |
| log.trace("Returning new connection " + connectionInfo.getManagedConnectionInfo()); |
| } |
| if (connectionCount < minSize) { |
| timer.schedule(new FillTask(connectionInfo), 10); |
| } |
| |
| } |
| } |
| |
| protected void doAdd(ManagedConnectionInfo mci) { |
| pool.put(mci.getManagedConnection(), mci); |
| } |
| |
| protected Object getPool() { |
| return pool; |
| } |
| |
| protected boolean doRemove(ManagedConnectionInfo mci) { |
| return pool.remove(mci.getManagedConnection()) == null; |
| } |
| |
| protected void internalDestroy() { |
| synchronized (pool) { |
| for (ManagedConnection managedConnection : pool.keySet()) { |
| try { |
| managedConnection.destroy(); |
| } catch (ResourceException ignore) { |
| } |
| } |
| pool.clear(); |
| } |
| } |
| |
| public int getIdleConnectionCount() { |
| synchronized (pool) { |
| return pool.size(); |
| } |
| } |
| |
| protected void transferConnections(int maxSize, int shrinkNow) { |
| List<ConnectionInfo> killList = new ArrayList<ConnectionInfo>(shrinkNow); |
| Iterator<Map.Entry<ManagedConnection, ManagedConnectionInfo>> it = pool.entrySet().iterator(); |
| for (int i = 0; i < shrinkNow; i++) { |
| killList.add(new ConnectionInfo(it.next().getValue())); |
| } |
| for (ConnectionInfo killInfo: killList) { |
| internalReturn(killInfo, ConnectionReturnAction.DESTROY); |
| } |
| } |
| |
| protected void getExpiredManagedConnectionInfos(long threshold, List<ManagedConnectionInfo> killList) { |
| synchronized (pool) { |
| for (ManagedConnectionInfo mci : pool.values()) { |
| if (mci.getLastUsed() < threshold) { |
| killList.add(mci); |
| } |
| } |
| } |
| |
| } |
| |
| } |