KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > connector > outbound > SinglePoolConnectionInterceptor


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.geronimo.connector.outbound;
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import javax.resource.ResourceException JavaDoc;
24 import javax.resource.spi.ManagedConnection JavaDoc;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 /**
30  * SinglePoolConnectionInterceptor chooses a single connection from the pool. If selectOneAssumeMatch
31  * is true, it simply returns the selected connection.
32  * THIS SHOULD BE USED ONLY IF MAXIMUM SPEED IS ESSENTIAL AND YOU HAVE THOROUGLY CHECKED THAT
33  * MATCHING WOULD SUCCEED ON THE SELECTED CONNECTION. (i.e., read the docs on your connector
34  * to find out how matching works)
35  * If selectOneAssumeMatch is false, it checks with the ManagedConnectionFactory that the
36  * selected connection does match before returning it: if not it throws an exception.
37  *
38  * @version $Rev: 483310 $ $Date: 2006-12-06 19:29:29 -0500 (Wed, 06 Dec 2006) $
39  */

40 public class SinglePoolConnectionInterceptor extends AbstractSinglePoolConnectionInterceptor {
41     private static final Log log = LogFactory.getLog(SinglePoolConnectionInterceptor.class.getName());
42
43     private boolean selectOneAssumeMatch;
44
45     private PoolDeque pool;
46
47     public SinglePoolConnectionInterceptor(final ConnectionInterceptor next,
48                                            int maxSize,
49                                            int minSize,
50                                            int blockingTimeoutMilliseconds,
51                                            int idleTimeoutMinutes,
52                                            boolean selectOneAssumeMatch) {
53         super(next, maxSize, minSize, blockingTimeoutMilliseconds, idleTimeoutMinutes);
54         pool = new PoolDeque(maxSize);
55         this.selectOneAssumeMatch = selectOneAssumeMatch;
56     }
57
58     protected void internalGetConnection(ConnectionInfo connectionInfo) throws ResourceException JavaDoc {
59         synchronized (pool) {
60             if (destroyed) {
61                 throw new ResourceException JavaDoc("ManagedConnection pool has been destroyed");
62             }
63
64             ManagedConnectionInfo newMCI = null;
65             if (pool.isEmpty()) {
66                 next.getConnection(connectionInfo);
67                 connectionCount++;
68                 if (log.isTraceEnabled()) {
69                     log.trace("Supplying new connection MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this);
70                 }
71                 return;
72             } else {
73                 newMCI = pool.removeLast();
74             }
75             if (connectionCount < minSize) {
76                 timer.schedule(new FillTask(connectionInfo), 10);
77             }
78             if (selectOneAssumeMatch) {
79                 connectionInfo.setManagedConnectionInfo(newMCI);
80                 if (log.isTraceEnabled()) {
81                     log.trace("Supplying pooled connection without checking matching MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this);
82                 }
83                 return;
84             }
85             try {
86                 ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
87                 ManagedConnection JavaDoc matchedMC =
88                         newMCI
89                         .getManagedConnectionFactory()
90                         .matchManagedConnections(Collections.singleton(newMCI.getManagedConnection()),
91                                 mci.getSubject(),
92                                 mci.getConnectionRequestInfo());
93                 if (matchedMC != null) {
94                     connectionInfo.setManagedConnectionInfo(newMCI);
95                     if (log.isTraceEnabled()) {
96                         log.trace("Supplying pooled connection MCI: " + connectionInfo.getManagedConnectionInfo() + " MC: " + connectionInfo.getManagedConnectionInfo().getManagedConnection() + " from pool: " + this);
97                     }
98                     return;
99                 } else {
100                     //matching failed.
101
ConnectionInfo returnCI = new ConnectionInfo();
102                     returnCI.setManagedConnectionInfo(newMCI);
103                     returnConnection(returnCI,
104                             ConnectionReturnAction.RETURN_HANDLE);
105                     throw new ResourceException JavaDoc("The pooling strategy does not match the MatchManagedConnections implementation. Please investigate and reconfigure this pool");
106                 }
107             } catch (ResourceException JavaDoc e) {
108                 //something is wrong: destroy connection, rethrow, release permit
109
ConnectionInfo returnCI = new ConnectionInfo();
110                 returnCI.setManagedConnectionInfo(newMCI);
111                 returnConnection(returnCI,
112                         ConnectionReturnAction.DESTROY);
113                 throw e;
114             }
115         }
116     }
117
118     protected void internalDestroy() {
119         synchronized (pool) {
120             while (!pool.isEmpty()) {
121                 ManagedConnection JavaDoc mc = pool.removeLast().getManagedConnection();
122                 if (mc != null) {
123                     try {
124                         mc.destroy();
125                     }
126                     catch (ResourceException JavaDoc re) { } // ignore
127
}
128             }
129         }
130     }
131
132     protected boolean internalReturn(ConnectionInfo connectionInfo, ConnectionReturnAction connectionReturnAction) {
133         ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
134         ManagedConnection JavaDoc mc = mci.getManagedConnection();
135         if (connectionReturnAction == ConnectionReturnAction.RETURN_HANDLE) {
136             try {
137                 mc.cleanup();
138             } catch (ResourceException JavaDoc e) {
139                 connectionReturnAction = ConnectionReturnAction.DESTROY;
140             }
141         }
142         boolean wasInPool = false;
143         synchronized (pool) {
144             // a bit redundant with returnConnection check in AbstractSinglePoolConnectionInterceptor,
145
// but checking here closes a small timing hole...
146
if (destroyed) {
147                 try {
148                     mc.destroy();
149                 }
150                 catch (ResourceException JavaDoc re) { } // ignore
151
return pool.remove(mci);
152             }
153
154             if (shrinkLater > 0) {
155                 //nothing can get in the pool while shrinkLater > 0, so wasInPool is false here.
156
connectionReturnAction = ConnectionReturnAction.DESTROY;
157                 shrinkLater--;
158             } else if (connectionReturnAction == ConnectionReturnAction.RETURN_HANDLE) {
159                 mci.setLastUsed(System.currentTimeMillis());
160                 pool.add(mci);
161                 return wasInPool;
162             } else {
163                 wasInPool = pool.remove(mci);
164             }
165         }
166         //we must destroy connection.
167
next.returnConnection(connectionInfo, connectionReturnAction);
168         connectionCount--;
169         return wasInPool;
170     }
171
172     public int getPartitionMaxSize() {
173         return pool.capacity();
174     }
175
176     protected void transferConnections(int maxSize, int shrinkNow) {
177         //1st example: copy 0 (none)
178
//2nd example: copy 10 (all)
179
PoolDeque oldPool = pool;
180         pool = new PoolDeque(maxSize);
181         //since we have replaced pool already, pool.remove will be very fast:-)
182
for (int i = 0; i < shrinkNow; i++) {
183             ConnectionInfo killInfo = new ConnectionInfo(oldPool.peek(i));
184             internalReturn(killInfo, ConnectionReturnAction.DESTROY);
185         }
186         for (int i = shrinkNow; i < connectionCount; i++) {
187             pool.add(oldPool.peek(i));
188         }
189     }
190
191     public int getIdleConnectionCount() {
192         return pool.currentSize();
193     }
194
195
196     protected void getExpiredManagedConnectionInfos(long threshold, ArrayList JavaDoc killList) {
197         synchronized (pool) {
198             for (int i = 0; i < pool.currentSize(); i++) {
199                 ManagedConnectionInfo mci = pool.peek(i);
200                 if (mci.getLastUsed() < threshold) {
201                     killList.add(mci);
202                 }
203             }
204         }
205     }
206
207     protected boolean addToPool(ManagedConnectionInfo mci) {
208         boolean added;
209         synchronized (pool) {
210             connectionCount++;
211             added = getPartitionMaxSize() > getIdleConnectionCount();
212             if (added) {
213                 pool.add(mci);
214             }
215         }
216         return added;
217     }
218
219     static class PoolDeque {
220
221         private final ManagedConnectionInfo[] deque;
222         private final int first = 0;
223         private int last = -1;
224
225         public PoolDeque(int size) {
226             deque = new ManagedConnectionInfo[size];
227         }
228
229         //internal
230
public boolean isEmpty() {
231             return first > last;
232         }
233
234         //internal
235
public void add(ManagedConnectionInfo mci) {
236             if (last == deque.length - 1) {
237                 throw new IllegalStateException JavaDoc("deque is full: contents: " + Arrays.asList(deque));
238             }
239             deque[++last] = mci;
240         }
241
242         //internal
243
public ManagedConnectionInfo peek(int i) {
244             if (i < first || i > last) {
245                 throw new IllegalStateException JavaDoc("index is out of current range");
246             }
247             return deque[i];
248         }
249
250         //internal
251
public ManagedConnectionInfo removeLast() {
252             if (isEmpty()) {
253                 throw new IllegalStateException JavaDoc("deque is empty");
254             }
255
256             return deque[last--];
257         }
258
259         //internal
260
public boolean remove(ManagedConnectionInfo mci) {
261             for (int i = first; i <= last; i++) {
262                 if (deque[i] == mci) {
263                     for (int j = i + 1; j <= last; j++) {
264                         deque[j - 1] = deque[j];
265                     }
266                     last--;
267                     return true;
268                 }
269
270             }
271             return false;
272         }
273
274         //internal
275
public int capacity() {
276             return deque.length;
277         }
278
279         //internal
280
public int currentSize() {
281             return last - first + 1;
282         }
283     }
284
285 }
286
Popular Tags