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