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              public int getMaxForRoute(final HttpRoute unused) {
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