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 }