-
Notifications
You must be signed in to change notification settings - Fork 11
/
SinglePoolConnectionInterceptor.java
185 lines (164 loc) · 7.7 KB
/
SinglePoolConnectionInterceptor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/**
* 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.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.resource.ResourceException;
import javax.resource.spi.ManagedConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* SinglePoolConnectionInterceptor chooses a single connection from the pool. If selectOneAssumeMatch
* is true, it simply returns the selected connection.
* THIS SHOULD BE USED ONLY IF MAXIMUM SPEED IS ESSENTIAL AND YOU HAVE THOROUGLY CHECKED THAT
* MATCHING WOULD SUCCEED ON THE SELECTED CONNECTION. (i.e., read the docs on your connector
* to find out how matching works)
* If selectOneAssumeMatch is false, it checks with the ManagedConnectionFactory that the
* selected connection does match before returning it: if not it throws an exception.
*
* @version $Rev$ $Date$
*/
public class SinglePoolConnectionInterceptor extends AbstractSinglePoolConnectionInterceptor {
private static final Logger log = LoggerFactory.getLogger(SinglePoolConnectionInterceptor.class.getName());
private boolean selectOneAssumeMatch;
//pool is mutable but only changed when protected by write lock on resizelock in superclass
private final List<ManagedConnectionInfo> pool;
public SinglePoolConnectionInterceptor(final ConnectionInterceptor next,
int maxSize,
int minSize,
int blockingTimeoutMilliseconds,
int idleTimeoutMinutes,
boolean selectOneAssumeMatch) {
super(next, maxSize, minSize, blockingTimeoutMilliseconds, idleTimeoutMinutes);
pool = new ArrayList<ManagedConnectionInfo>(maxSize);
this.selectOneAssumeMatch = selectOneAssumeMatch;
}
protected void internalGetConnection(ConnectionInfo connectionInfo) throws ResourceException {
synchronized (pool) {
if (destroyed) {
throw new ResourceException("ManagedConnection pool has been destroyed");
}
ManagedConnectionInfo newMCI;
if (pool.isEmpty()) {
next.getConnection(connectionInfo);
connectionCount++;
if (log.isTraceEnabled()) {
log.trace("Supplying new connection MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this);
}
return;
} else {
newMCI = pool.remove(pool.size() - 1);
}
if (connectionCount < minSize) {
timer.schedule(new FillTask(connectionInfo), 10);
}
if (selectOneAssumeMatch) {
connectionInfo.setManagedConnectionInfo(newMCI);
if (log.isTraceEnabled()) {
log.trace("Supplying pooled connection without checking matching MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this);
}
return;
}
ManagedConnection matchedMC;
try {
ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
matchedMC = newMCI.getManagedConnectionFactory().matchManagedConnections(Collections.singleton(newMCI.getManagedConnection()),
mci.getSubject(),
mci.getConnectionRequestInfo());
} catch (ResourceException e) {
//something is wrong: destroy connection, rethrow, release permit
ConnectionInfo returnCI = new ConnectionInfo();
returnCI.setManagedConnectionInfo(newMCI);
returnConnection(returnCI, ConnectionReturnAction.DESTROY);
throw e;
}
if (matchedMC != null) {
connectionInfo.setManagedConnectionInfo(newMCI);
if (log.isTraceEnabled()) {
log.trace("Supplying pooled connection MCI: " + connectionInfo.getManagedConnectionInfo() + " from pool: " + this);
}
} else {
//matching failed.
ConnectionInfo returnCI = new ConnectionInfo();
returnCI.setManagedConnectionInfo(newMCI);
returnConnection(returnCI, ConnectionReturnAction.RETURN_HANDLE);
throw new ResourceException("The pooling strategy does not match the MatchManagedConnections implementation. Please investigate and reconfigure this pool");
}
}
}
protected void internalDestroy() {
synchronized (pool) {
while (!pool.isEmpty()) {
ManagedConnection mc = pool.remove(pool.size() - 1).getManagedConnection();
if (mc != null) {
try {
mc.destroy();
}
catch (ResourceException re) {
//ignore
}
}
}
}
}
protected Object getPool() {
return pool;
}
protected void doAdd(ManagedConnectionInfo mci) {
pool.add(mci);
}
/**
* @param mci managedConnectionInfo to remove from pool
* @return true if mci was not in pool already, false if mci was in pool already.
*/
protected boolean doRemove(ManagedConnectionInfo mci) {
log.info("Removing " + mci + " from pool " + this);
return !pool.remove(mci);
}
protected void transferConnections(int maxSize, int shrinkNow) {
for (int i = 0; i < shrinkNow; i++) {
ConnectionInfo killInfo = new ConnectionInfo(pool.get(0));
internalReturn(killInfo, ConnectionReturnAction.DESTROY);
}
}
public int getIdleConnectionCount() {
return pool.size();
}
protected void getExpiredManagedConnectionInfos(long threshold, List<ManagedConnectionInfo> killList) {
synchronized (pool) {
for (Iterator<ManagedConnectionInfo> mcis = pool.iterator(); mcis.hasNext(); ) {
ManagedConnectionInfo mci = mcis.next();
if (mci.getLastUsed() < threshold) {
mcis.remove();
killList.add(mci);
connectionCount--;
}
}
}
}
public void info(StringBuilder s) {
s.append(getClass().getName());
s.append("[minSize=").append(minSize);
s.append(",maxSize=").append(maxSize);
s.append(",idleTimeoutMilliseconds=").append(idleTimeoutMilliseconds);
s.append(",blockingTimeoutMilliseconds=").append(blockingTimeoutMilliseconds);
s.append(".selectOneAssumeMatch=").append(selectOneAssumeMatch).append("]\n");
next.info(s);
}
}