View Javadoc

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              @Override
88              public int getMaxForRoute(final HttpRoute unused) {
89                  return RouteSpecificPool.this.maxEntries;
90              }
91          };
92          this.freeEntries = new LinkedList<BasicPoolEntry>();
93          this.waitingThreads = new LinkedList<WaitingThread>();
94          this.numEntries = 0;
95      }
96  
97  
98      /**
99       * Creates a new route-specific pool.
100      *
101      * @param route the route for which to pool
102      * @param connPerRoute the connections per route configuration
103      */
104     public RouteSpecificPool(final HttpRoute route, final ConnPerRoute connPerRoute) {
105         this.route = route;
106         this.connPerRoute = connPerRoute;
107         this.maxEntries = connPerRoute.getMaxForRoute(route);
108         this.freeEntries = new LinkedList<BasicPoolEntry>();
109         this.waitingThreads = new LinkedList<WaitingThread>();
110         this.numEntries = 0;
111     }
112 
113 
114     /**
115      * Obtains the route for which this pool is specific.
116      *
117      * @return  the route
118      */
119     public final HttpRoute getRoute() {
120         return route;
121     }
122 
123 
124     /**
125      * Obtains the maximum number of entries allowed for this pool.
126      *
127      * @return  the max entry number
128      */
129     public final int getMaxEntries() {
130         return maxEntries;
131     }
132 
133 
134     /**
135      * Indicates whether this pool is unused.
136      * A pool is unused if there is neither an entry nor a waiting thread.
137      * All entries count, not only the free but also the allocated ones.
138      *
139      * @return  {@code true} if this pool is unused,
140      *          {@code false} otherwise
141      */
142     public boolean isUnused() {
143         return (numEntries < 1) && waitingThreads.isEmpty();
144     }
145 
146 
147     /**
148      * Return remaining capacity of this pool
149      *
150      * @return capacity
151      */
152     public int getCapacity() {
153         return connPerRoute.getMaxForRoute(route) - numEntries;
154     }
155 
156 
157     /**
158      * Obtains the number of entries.
159      * This includes not only the free entries, but also those that
160      * have been created and are currently issued to an application.
161      *
162      * @return  the number of entries for the route of this pool
163      */
164     public final int getEntryCount() {
165         return numEntries;
166     }
167 
168 
169     /**
170      * Obtains a free entry from this pool, if one is available.
171      *
172      * @return an available pool entry, or {@code null} if there is none
173      */
174     public BasicPoolEntry allocEntry(final Object state) {
175         if (!freeEntries.isEmpty()) {
176             final ListIterator<BasicPoolEntry> it = freeEntries.listIterator(freeEntries.size());
177             while (it.hasPrevious()) {
178                 final BasicPoolEntry entry = it.previous();
179                 if (entry.getState() == null || LangUtils.equals(state, entry.getState())) {
180                     it.remove();
181                     return entry;
182                 }
183             }
184         }
185         if (getCapacity() == 0 && !freeEntries.isEmpty()) {
186             final BasicPoolEntry entry = freeEntries.remove();
187             entry.shutdownEntry();
188             final OperatedClientConnection conn = entry.getConnection();
189             try {
190                 conn.close();
191             } catch (final IOException ex) {
192                 log.debug("I/O error closing connection", ex);
193             }
194             return entry;
195         }
196         return null;
197     }
198 
199 
200     /**
201      * Returns an allocated entry to this pool.
202      *
203      * @param entry     the entry obtained from {@link #allocEntry allocEntry}
204      *                  or presented to {@link #createdEntry createdEntry}
205      */
206     public void freeEntry(final BasicPoolEntry entry) {
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(final BasicPoolEntry entry) {
228         Args.check(route.equals(entry.getPlannedRoute()), "Entry not planned for this pool");
229         numEntries++;
230     }
231 
232 
233     /**
234      * Deletes an entry from this pool.
235      * Only entries that are currently free in this pool can be deleted.
236      * Allocated entries can not be deleted.
237      *
238      * @param entry     the entry to delete from this pool
239      *
240      * @return  {@code true} if the entry was found and deleted, or
241      *          {@code false} if the entry was not found
242      */
243     public boolean deleteEntry(final BasicPoolEntry entry) {
244 
245         final boolean found = freeEntries.remove(entry);
246         if (found) {
247             numEntries--;
248         }
249         return found;
250     }
251 
252 
253     /**
254      * Forgets about an entry from this pool.
255      * This method is used to indicate that an entry
256      * {@link #allocEntry allocated}
257      * from this pool has been lost and will not be returned.
258      */
259     public void dropEntry() {
260         Asserts.check(numEntries > 0, "There is no entry that could be dropped");
261         numEntries--;
262     }
263 
264 
265     /**
266      * Adds a waiting thread.
267      * This pool makes no attempt to match waiting threads with pool entries.
268      * It is the caller's responsibility to check that there is no entry
269      * before adding a waiting thread.
270      *
271      * @param wt        the waiting thread
272      */
273     public void queueThread(final WaitingThread wt) {
274         Args.notNull(wt, "Waiting thread");
275         this.waitingThreads.add(wt);
276     }
277 
278 
279     /**
280      * Checks whether there is a waiting thread in this pool.
281      *
282      * @return  {@code true} if there is a waiting thread,
283      *          {@code false} otherwise
284      */
285     public boolean hasThread() {
286         return !this.waitingThreads.isEmpty();
287     }
288 
289 
290     /**
291      * Returns the next thread in the queue.
292      *
293      * @return  a waiting thread, or {@code null} if there is none
294      */
295     public WaitingThread nextThread() {
296         return this.waitingThreads.peek();
297     }
298 
299 
300     /**
301      * Removes a waiting thread, if it is queued.
302      *
303      * @param wt        the waiting thread
304      */
305     public void removeThread(final WaitingThread wt) {
306         if (wt == null) {
307             return;
308         }
309 
310         this.waitingThreads.remove(wt);
311     }
312 
313 
314 } // class RouteSpecificPool