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