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.nio.pool;
28  
29  import java.net.ConnectException;
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.LinkedList;
34  import java.util.Map;
35  import java.util.Set;
36  
37  import org.apache.http.concurrent.BasicFuture;
38  import org.apache.http.nio.reactor.SessionRequest;
39  import org.apache.http.pool.PoolEntry;
40  import org.apache.http.util.Args;
41  import org.apache.http.util.Asserts;
42  
43  abstract class RouteSpecificPool<T, C, E extends PoolEntry<T, C>> {
44  
45      private final T route;
46      private final Set<E> leased;
47      private final LinkedList<E> available;
48      private final Map<SessionRequest, BasicFuture<E>> pending;
49  
50      RouteSpecificPool(final T route) {
51          super();
52          this.route = route;
53          this.leased = new HashSet<E>();
54          this.available = new LinkedList<E>();
55          this.pending = new HashMap<SessionRequest, BasicFuture<E>>();
56      }
57  
58      public T getRoute() {
59          return this.route;
60      }
61  
62      protected abstract E createEntry(T route, C conn);
63  
64      public int getLeasedCount() {
65          return this.leased.size();
66      }
67  
68      public int getPendingCount() {
69          return this.pending.size();
70      }
71  
72      public int getAvailableCount() {
73          return this.available.size();
74      }
75  
76      public int getAllocatedCount() {
77          return this.available.size() + this.leased.size() + this.pending.size();
78      }
79  
80      public E getFree(final Object state) {
81          if (!this.available.isEmpty()) {
82              if (state != null) {
83                  final Iterator<E> it = this.available.iterator();
84                  while (it.hasNext()) {
85                      final E entry = it.next();
86                      if (state.equals(entry.getState())) {
87                          it.remove();
88                          this.leased.add(entry);
89                          return entry;
90                      }
91                  }
92              }
93              final Iterator<E> it = this.available.iterator();
94              while (it.hasNext()) {
95                  final E entry = it.next();
96                  if (entry.getState() == null) {
97                      it.remove();
98                      this.leased.add(entry);
99                      return entry;
100                 }
101             }
102         }
103         return null;
104     }
105 
106     public E getLastUsed() {
107         if (!this.available.isEmpty()) {
108             return this.available.getLast();
109         } else {
110             return null;
111         }
112     }
113 
114     public boolean remove(final E entry) {
115         Args.notNull(entry, "Pool entry");
116         if (!this.available.remove(entry)) {
117             if (!this.leased.remove(entry)) {
118                 return false;
119             }
120         }
121         return true;
122     }
123 
124     public void free(final E entry, final boolean reusable) {
125         Args.notNull(entry, "Pool entry");
126         final boolean found = this.leased.remove(entry);
127         Asserts.check(found, "Entry %s has not been leased from this pool", entry);
128         if (reusable) {
129             this.available.addFirst(entry);
130         }
131     }
132 
133     public void addPending(final SessionRequest request, final BasicFuture<E> future) {
134         this.pending.put(request, future);
135     }
136 
137     private BasicFuture<E> removeRequest(final SessionRequest request) {
138         return this.pending.remove(request);
139     }
140 
141     public E createEntry(final SessionRequest request, final C conn) {
142         final E entry = createEntry(this.route, conn);
143         this.leased.add(entry);
144         return entry;
145     }
146 
147     public boolean completed(final SessionRequest request, final E entry) {
148         final BasicFuture<E> future = removeRequest(request);
149         if (future != null) {
150             return future.completed(entry);
151         } else {
152             request.cancel();
153             return false;
154         }
155     }
156 
157     public void cancelled(final SessionRequest request) {
158         final BasicFuture<E> future = removeRequest(request);
159         if (future != null) {
160             future.cancel(true);
161         }
162     }
163 
164     public void failed(final SessionRequest request, final Exception ex) {
165         final BasicFuture<E> future = removeRequest(request);
166         if (future != null) {
167             future.failed(ex);
168         }
169     }
170 
171     public void timeout(final SessionRequest request) {
172         final BasicFuture<E> future = removeRequest(request);
173         if (future != null) {
174             future.failed(new ConnectException());
175         }
176     }
177 
178     public void shutdown() {
179         for (final SessionRequest request: this.pending.keySet()) {
180             request.cancel();
181         }
182         this.pending.clear();
183         for (final E entry: this.available) {
184             entry.close();
185         }
186         this.available.clear();
187         for (final E entry: this.leased) {
188             entry.close();
189         }
190         this.leased.clear();
191     }
192 
193     @Override
194     public String toString() {
195         final StringBuilder buffer = new StringBuilder();
196         buffer.append("[route: ");
197         buffer.append(this.route);
198         buffer.append("][leased: ");
199         buffer.append(this.leased.size());
200         buffer.append("][available: ");
201         buffer.append(this.available.size());
202         buffer.append("][pending: ");
203         buffer.append(this.pending.size());
204         buffer.append("]");
205         return buffer.toString();
206     }
207 
208 }