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.ArrayList; 021 import java.util.Collections; 022 import java.util.List; 023 024 import javax.resource.ResourceException; 025 import javax.resource.spi.ManagedConnection; 026 027 import org.apache.commons.logging.Log; 028 import org.apache.commons.logging.LogFactory; 029 030 /** 031 * SinglePoolConnectionInterceptor chooses a single connection from the pool. If selectOneAssumeMatch 032 * is true, it simply returns the selected connection. 033 * THIS SHOULD BE USED ONLY IF MAXIMUM SPEED IS ESSENTIAL AND YOU HAVE THOROUGLY CHECKED THAT 034 * MATCHING WOULD SUCCEED ON THE SELECTED CONNECTION. (i.e., read the docs on your connector 035 * to find out how matching works) 036 * If selectOneAssumeMatch is false, it checks with the ManagedConnectionFactory that the 037 * selected connection does match before returning it: if not it throws an exception. 038 * 039 * @version $Rev: 620213 $ $Date: 2008-02-10 00:13:09 +0100 (Sun, 10 Feb 2008) $ 040 */ 041 public class SinglePoolConnectionInterceptor extends AbstractSinglePoolConnectionInterceptor { 042 private static final Log log = LogFactory.getLog(SinglePoolConnectionInterceptor.class.getName()); 043 044 private boolean selectOneAssumeMatch; 045 046 //pool is mutable but only changed when protected by write lock on resizelock in superclass 047 // private PoolDeque pool; 048 private final List<ManagedConnectionInfo> pool; 049 050 public SinglePoolConnectionInterceptor(final ConnectionInterceptor next, 051 int maxSize, 052 int minSize, 053 int blockingTimeoutMilliseconds, 054 int idleTimeoutMinutes, 055 boolean selectOneAssumeMatch) { 056 super(next, maxSize, minSize, blockingTimeoutMilliseconds, idleTimeoutMinutes); 057 // pool = new PoolDeque(maxSize); 058 pool = new ArrayList<ManagedConnectionInfo>(maxSize); 059 this.selectOneAssumeMatch = selectOneAssumeMatch; 060 } 061 062 protected void internalGetConnection(ConnectionInfo connectionInfo) throws ResourceException { 063 synchronized (pool) { 064 if (destroyed) { 065 throw new ResourceException("ManagedConnection pool has been destroyed"); 066 } 067 068 ManagedConnectionInfo newMCI; 069 if (pool.isEmpty()) { 070 next.getConnection(connectionInfo); 071 connectionCount++; 072 if (log.isTraceEnabled()) { 073 log.trace("Supplying new connection MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this); 074 } 075 return; 076 } else { 077 newMCI = pool.remove(pool.size() - 1); 078 } 079 if (connectionCount < minSize) { 080 timer.schedule(new FillTask(connectionInfo), 10); 081 } 082 if (selectOneAssumeMatch) { 083 connectionInfo.setManagedConnectionInfo(newMCI); 084 if (log.isTraceEnabled()) { 085 log.trace("Supplying pooled connection without checking matching MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this); 086 } 087 return; 088 } 089 try { 090 ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo(); 091 ManagedConnection matchedMC = newMCI.getManagedConnectionFactory().matchManagedConnections(Collections.singleton(newMCI.getManagedConnection()), 092 mci.getSubject(), 093 mci.getConnectionRequestInfo()); 094 if (matchedMC != null) { 095 connectionInfo.setManagedConnectionInfo(newMCI); 096 if (log.isTraceEnabled()) { 097 log.trace("Supplying pooled connection MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this); 098 } 099 } else { 100 //matching failed. 101 ConnectionInfo returnCI = new ConnectionInfo(); 102 returnCI.setManagedConnectionInfo(newMCI); 103 returnConnection(returnCI, ConnectionReturnAction.RETURN_HANDLE); 104 throw new ResourceException("The pooling strategy does not match the MatchManagedConnections implementation. Please investigate and reconfigure this pool"); 105 } 106 } catch (ResourceException e) { 107 //something is wrong: destroy connection, rethrow, release permit 108 ConnectionInfo returnCI = new ConnectionInfo(); 109 returnCI.setManagedConnectionInfo(newMCI); 110 returnConnection(returnCI, ConnectionReturnAction.DESTROY); 111 throw e; 112 } 113 } 114 } 115 116 protected void internalDestroy() { 117 synchronized (pool) { 118 while (!pool.isEmpty()) { 119 ManagedConnection mc = pool.remove(pool.size() - 1).getManagedConnection(); 120 if (mc != null) { 121 try { 122 mc.destroy(); 123 } 124 catch (ResourceException re) { 125 //ignore 126 } 127 } 128 } 129 } 130 } 131 132 protected Object getPool() { 133 return pool; 134 } 135 136 protected void doAdd(ManagedConnectionInfo mci) { 137 pool.add(mci); 138 } 139 140 protected boolean doRemove(ManagedConnectionInfo mci) { 141 return !pool.remove(mci); 142 } 143 144 protected void transferConnections(int maxSize, int shrinkNow) { 145 for (int i = 0; i < shrinkNow; i++) { 146 ConnectionInfo killInfo = new ConnectionInfo(pool.get(0)); 147 internalReturn(killInfo, ConnectionReturnAction.DESTROY); 148 } 149 } 150 151 public int getIdleConnectionCount() { 152 return pool.size(); 153 } 154 155 156 protected void getExpiredManagedConnectionInfos(long threshold, List<ManagedConnectionInfo> killList) { 157 synchronized (pool) { 158 for (ManagedConnectionInfo mci : pool) { 159 if (mci.getLastUsed() < threshold) { 160 killList.add(mci); 161 } 162 } 163 } 164 } 165 166 }