1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27 package org.apache.http.impl.conn.tsccm;
28
29 import java.io.IOException;
30 import java.util.LinkedList;
31 import java.util.ListIterator;
32 import java.util.Queue;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.http.conn.OperatedClientConnection;
37 import org.apache.http.conn.params.ConnPerRoute;
38 import org.apache.http.conn.routing.HttpRoute;
39 import org.apache.http.util.Args;
40 import org.apache.http.util.Asserts;
41 import org.apache.http.util.LangUtils;
42
43
44 /**
45 * A connection sub-pool for a specific route, used by {@link ConnPoolByRoute}.
46 * The methods in this class are unsynchronized. It is expected that the
47 * containing pool takes care of synchronization.
48 *
49 * @since 4.0
50 *
51 * @deprecated (4.2) use {@link org.apache.http.pool.AbstractConnPool}
52 */
53 @Deprecated
54 public class RouteSpecificPool {
55
56 private final Log log = LogFactory.getLog(getClass());
57
58 /** The route this pool is for. */
59 protected final HttpRoute route; //Immutable
60
61 protected final int maxEntries;
62
63 /** Connections per route */
64 protected final ConnPerRoute connPerRoute;
65
66 /**
67 * The list of free entries.
68 * This list is managed LIFO, to increase idle times and
69 * allow for closing connections that are not really needed.
70 */
71 protected final LinkedList<BasicPoolEntry> freeEntries;
72
73 /** The list of threads waiting for this pool. */
74 protected final Queue<WaitingThread> waitingThreads;
75
76 /** The number of created entries. */
77 protected int numEntries;
78
79 /**
80 * @deprecated (4.1) use {@link RouteSpecificPool#RouteSpecificPool(HttpRoute, ConnPerRoute)}
81 */
82 @Deprecated
83 public RouteSpecificPool(final HttpRoute route, final int maxEntries) {
84 this.route = route;
85 this.maxEntries = maxEntries;
86 this.connPerRoute = new ConnPerRoute() {
87 public int getMaxForRoute(final HttpRoute route) {
88 return RouteSpecificPool.this.maxEntries;
89 }
90 };
91 this.freeEntries = new LinkedList<BasicPoolEntry>();
92 this.waitingThreads = new LinkedList<WaitingThread>();
93 this.numEntries = 0;
94 }
95
96
97 /**
98 * Creates a new route-specific pool.
99 *
100 * @param route the route for which to pool
101 * @param connPerRoute the connections per route configuration
102 */
103 public RouteSpecificPool(final HttpRoute route, final ConnPerRoute connPerRoute) {
104 this.route = route;
105 this.connPerRoute = connPerRoute;
106 this.maxEntries = connPerRoute.getMaxForRoute(route);
107 this.freeEntries = new LinkedList<BasicPoolEntry>();
108 this.waitingThreads = new LinkedList<WaitingThread>();
109 this.numEntries = 0;
110 }
111
112
113 /**
114 * Obtains the route for which this pool is specific.
115 *
116 * @return the route
117 */
118 public final HttpRoute getRoute() {
119 return route;
120 }
121
122
123 /**
124 * Obtains the maximum number of entries allowed for this pool.
125 *
126 * @return the max entry number
127 */
128 public final int getMaxEntries() {
129 return maxEntries;
130 }
131
132
133 /**
134 * Indicates whether this pool is unused.
135 * A pool is unused if there is neither an entry nor a waiting thread.
136 * All entries count, not only the free but also the allocated ones.
137 *
138 * @return <code>true</code> if this pool is unused,
139 * <code>false</code> otherwise
140 */
141 public boolean isUnused() {
142 return (numEntries < 1) && waitingThreads.isEmpty();
143 }
144
145
146 /**
147 * Return remaining capacity of this pool
148 *
149 * @return capacity
150 */
151 public int getCapacity() {
152 return connPerRoute.getMaxForRoute(route) - numEntries;
153 }
154
155
156 /**
157 * Obtains the number of entries.
158 * This includes not only the free entries, but also those that
159 * have been created and are currently issued to an application.
160 *
161 * @return the number of entries for the route of this pool
162 */
163 public final int getEntryCount() {
164 return numEntries;
165 }
166
167
168 /**
169 * Obtains a free entry from this pool, if one is available.
170 *
171 * @return an available pool entry, or <code>null</code> if there is none
172 */
173 public BasicPoolEntry allocEntry(final Object state) {
174 if (!freeEntries.isEmpty()) {
175 final ListIterator<BasicPoolEntry> it = freeEntries.listIterator(freeEntries.size());
176 while (it.hasPrevious()) {
177 final BasicPoolEntry entry = it.previous();
178 if (entry.getState() == null || LangUtils.equals(state, entry.getState())) {
179 it.remove();
180 return entry;
181 }
182 }
183 }
184 if (getCapacity() == 0 && !freeEntries.isEmpty()) {
185 final BasicPoolEntry entry = freeEntries.remove();
186 entry.shutdownEntry();
187 final OperatedClientConnection conn = entry.getConnection();
188 try {
189 conn.close();
190 } catch (final IOException ex) {
191 log.debug("I/O error closing connection", ex);
192 }
193 return entry;
194 }
195 return null;
196 }
197
198
199 /**
200 * Returns an allocated entry to this pool.
201 *
202 * @param entry the entry obtained from {@link #allocEntry allocEntry}
203 * or presented to {@link #createdEntry createdEntry}
204 */
205 public void freeEntry(final BasicPoolEntry entry) {
206 if (numEntries < 1) {
207 throw new IllegalStateException
208 ("No entry created for this pool. " + route);
209 }
210 if (numEntries <= freeEntries.size()) {
211 throw new IllegalStateException
212 ("No entry allocated from this pool. " + route);
213 }
214 freeEntries.add(entry);
215 }
216
217
218 /**
219 * Indicates creation of an entry for this pool.
220 * The entry will <i>not</i> be added to the list of free entries,
221 * it is only recognized as belonging to this pool now. It can then
222 * be passed to {@link #freeEntry freeEntry}.
223 *
224 * @param entry the entry that was created for this pool
225 */
226 public void createdEntry(final BasicPoolEntry entry) {
227 Args.check(route.equals(entry.getPlannedRoute()), "Entry not planned for this pool");
228 numEntries++;
229 }
230
231
232 /**
233 * Deletes an entry from this pool.
234 * Only entries that are currently free in this pool can be deleted.
235 * Allocated entries can not be deleted.
236 *
237 * @param entry the entry to delete from this pool
238 *
239 * @return <code>true</code> if the entry was found and deleted, or
240 * <code>false</code> if the entry was not found
241 */
242 public boolean deleteEntry(final BasicPoolEntry entry) {
243
244 final boolean found = freeEntries.remove(entry);
245 if (found) {
246 numEntries--;
247 }
248 return found;
249 }
250
251
252 /**
253 * Forgets about an entry from this pool.
254 * This method is used to indicate that an entry
255 * {@link #allocEntry allocated}
256 * from this pool has been lost and will not be returned.
257 */
258 public void dropEntry() {
259 Asserts.check(numEntries > 0, "There is no entry that could be dropped");
260 numEntries--;
261 }
262
263
264 /**
265 * Adds a waiting thread.
266 * This pool makes no attempt to match waiting threads with pool entries.
267 * It is the caller's responsibility to check that there is no entry
268 * before adding a waiting thread.
269 *
270 * @param wt the waiting thread
271 */
272 public void queueThread(final WaitingThread wt) {
273 Args.notNull(wt, "Waiting thread");
274 this.waitingThreads.add(wt);
275 }
276
277
278 /**
279 * Checks whether there is a waiting thread in this pool.
280 *
281 * @return <code>true</code> if there is a waiting thread,
282 * <code>false</code> otherwise
283 */
284 public boolean hasThread() {
285 return !this.waitingThreads.isEmpty();
286 }
287
288
289 /**
290 * Returns the next thread in the queue.
291 *
292 * @return a waiting thread, or <code>null</code> if there is none
293 */
294 public WaitingThread nextThread() {
295 return this.waitingThreads.peek();
296 }
297
298
299 /**
300 * Removes a waiting thread, if it is queued.
301 *
302 * @param wt the waiting thread
303 */
304 public void removeThread(final WaitingThread wt) {
305 if (wt == null) {
306 return;
307 }
308
309 this.waitingThreads.remove(wt);
310 }
311
312
313 } // class RouteSpecificPool