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
31package org.apache.http.impl.conn.tsccm;
32
33import java.io.IOException;
34import java.util.ListIterator;
35import java.util.Queue;
36import java.util.LinkedList;
37
38import org.apache.commons.logging.Log;
39import org.apache.commons.logging.LogFactory;
40import org.apache.http.conn.OperatedClientConnection;
41import org.apache.http.conn.routing.HttpRoute;
42import 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
55public 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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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