mobile/android/thirdparty/ch/boye/httpclientandroidlib/impl/conn/tsccm/RouteSpecificPool.java

branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
equal deleted inserted replaced
-1:000000000000 0:12f7b903a100
1 /*
2 * ====================================================================
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * 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, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ====================================================================
19 *
20 * This software consists of voluntary contributions made by many
21 * individuals on behalf of the Apache Software Foundation. For more
22 * information on the Apache Software Foundation, please see
23 * <http://www.apache.org/>.
24 *
25 */
26
27 package ch.boye.httpclientandroidlib.impl.conn.tsccm;
28
29 import java.io.IOException;
30 import java.util.ListIterator;
31 import java.util.Queue;
32 import java.util.LinkedList;
33
34 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
35
36 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog;
37 /* LogFactory removed by HttpClient for Android script. */
38 import ch.boye.httpclientandroidlib.conn.OperatedClientConnection;
39 import ch.boye.httpclientandroidlib.conn.params.ConnPerRoute;
40 import ch.boye.httpclientandroidlib.conn.routing.HttpRoute;
41 import ch.boye.httpclientandroidlib.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 @NotThreadSafe // e.g. numEntries, freeEntries,
52 public class RouteSpecificPool {
53
54 public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass());
55
56 /** The route this pool is for. */
57 protected final HttpRoute route; //Immutable
58
59 @Deprecated
60 protected final int maxEntries;
61
62 /** Connections per route */
63 protected final ConnPerRoute connPerRoute;
64
65 /**
66 * The list of free entries.
67 * This list is managed LIFO, to increase idle times and
68 * allow for closing connections that are not really needed.
69 */
70 protected final LinkedList<BasicPoolEntry> freeEntries;
71
72 /** The list of threads waiting for this pool. */
73 protected final Queue<WaitingThread> waitingThreads;
74
75 /** The number of created entries. */
76 protected int numEntries;
77
78
79 /**
80 * @deprecated use {@link RouteSpecificPool#RouteSpecificPool(HttpRoute, ConnPerRoute)}
81 */
82 @Deprecated
83 public RouteSpecificPool(HttpRoute route, int maxEntries) {
84 this.route = route;
85 this.maxEntries = maxEntries;
86 this.connPerRoute = new ConnPerRoute() {
87 public int getMaxForRoute(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(HttpRoute route, 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 ListIterator<BasicPoolEntry> it = freeEntries.listIterator(freeEntries.size());
176 while (it.hasPrevious()) {
177 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 BasicPoolEntry entry = freeEntries.remove();
186 entry.shutdownEntry();
187 OperatedClientConnection conn = entry.getConnection();
188 try {
189 conn.close();
190 } catch (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(BasicPoolEntry entry) {
206
207 if (numEntries < 1) {
208 throw new IllegalStateException
209 ("No entry created for this pool. " + route);
210 }
211 if (numEntries <= freeEntries.size()) {
212 throw new IllegalStateException
213 ("No entry allocated from this pool. " + route);
214 }
215 freeEntries.add(entry);
216 }
217
218
219 /**
220 * Indicates creation of an entry for this pool.
221 * The entry will <i>not</i> be added to the list of free entries,
222 * it is only recognized as belonging to this pool now. It can then
223 * be passed to {@link #freeEntry freeEntry}.
224 *
225 * @param entry the entry that was created for this pool
226 */
227 public void createdEntry(BasicPoolEntry entry) {
228
229 if (!route.equals(entry.getPlannedRoute())) {
230 throw new IllegalArgumentException
231 ("Entry not planned for this pool." +
232 "\npool: " + route +
233 "\nplan: " + entry.getPlannedRoute());
234 }
235
236 numEntries++;
237 }
238
239
240 /**
241 * Deletes an entry from this pool.
242 * Only entries that are currently free in this pool can be deleted.
243 * Allocated entries can not be deleted.
244 *
245 * @param entry the entry to delete from this pool
246 *
247 * @return <code>true</code> if the entry was found and deleted, or
248 * <code>false</code> if the entry was not found
249 */
250 public boolean deleteEntry(BasicPoolEntry entry) {
251
252 final boolean found = freeEntries.remove(entry);
253 if (found)
254 numEntries--;
255 return found;
256 }
257
258
259 /**
260 * Forgets about an entry from this pool.
261 * This method is used to indicate that an entry
262 * {@link #allocEntry allocated}
263 * from this pool has been lost and will not be returned.
264 */
265 public void dropEntry() {
266 if (numEntries < 1) {
267 throw new IllegalStateException
268 ("There is no entry that could be dropped.");
269 }
270 numEntries--;
271 }
272
273
274 /**
275 * Adds a waiting thread.
276 * This pool makes no attempt to match waiting threads with pool entries.
277 * It is the caller's responsibility to check that there is no entry
278 * before adding a waiting thread.
279 *
280 * @param wt the waiting thread
281 */
282 public void queueThread(WaitingThread wt) {
283 if (wt == null) {
284 throw new IllegalArgumentException
285 ("Waiting thread must not be null.");
286 }
287 this.waitingThreads.add(wt);
288 }
289
290
291 /**
292 * Checks whether there is a waiting thread in this pool.
293 *
294 * @return <code>true</code> if there is a waiting thread,
295 * <code>false</code> otherwise
296 */
297 public boolean hasThread() {
298 return !this.waitingThreads.isEmpty();
299 }
300
301
302 /**
303 * Returns the next thread in the queue.
304 *
305 * @return a waiting thread, or <code>null</code> if there is none
306 */
307 public WaitingThread nextThread() {
308 return this.waitingThreads.peek();
309 }
310
311
312 /**
313 * Removes a waiting thread, if it is queued.
314 *
315 * @param wt the waiting thread
316 */
317 public void removeThread(WaitingThread wt) {
318 if (wt == null)
319 return;
320
321 this.waitingThreads.remove(wt);
322 }
323
324
325 } // class RouteSpecificPool

mercurial