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         return this.available.isEmpty() ? null : this.available.getLast();
108     }
109 
110     public boolean remove(final E entry) {
111         Args.notNull(entry, "Pool entry");
112         if (!this.available.remove(entry)) {
113             if (!this.leased.remove(entry)) {
114                 return false;
115             }
116         }
117         return true;
118     }
119 
120     public void free(final E entry, final boolean reusable) {
121         Args.notNull(entry, "Pool entry");
122         final boolean found = this.leased.remove(entry);
123         Asserts.check(found, "Entry %s has not been leased from this pool", entry);
124         if (reusable) {
125             this.available.addFirst(entry);
126         }
127     }
128 
129     public void addPending(final SessionRequest request, final BasicFuture<E> future) {
130         this.pending.put(request, future);
131     }
132 
133     private BasicFuture<E> removeRequest(final SessionRequest request) {
134         return this.pending.remove(request);
135     }
136 
137     public E createEntry(final SessionRequest request, final C conn) {
138         final E entry = createEntry(this.route, conn);
139         this.leased.add(entry);
140         return entry;
141     }
142 
143     public boolean completed(final SessionRequest request, final E entry) {
144         final BasicFuture<E> future = removeRequest(request);
145         if (future != null) {
146             return future.completed(entry);
147         }
148         request.cancel();
149         return false;
150     }
151 
152     public void cancelled(final SessionRequest request) {
153         final BasicFuture<E> future = removeRequest(request);
154         if (future != null) {
155             future.cancel(true);
156         }
157     }
158 
159     public void failed(final SessionRequest request, final Exception ex) {
160         final BasicFuture<E> future = removeRequest(request);
161         if (future != null) {
162             future.failed(ex);
163         }
164     }
165 
166     public void timeout(final SessionRequest request) {
167         final BasicFuture<E> future = removeRequest(request);
168         if (future != null) {
169             future.failed(new ConnectException("Timeout connecting to [" + request.getRemoteAddress() + "]"));
170         }
171     }
172 
173     public void shutdown() {
174         for (final SessionRequest request: this.pending.keySet()) {
175             request.cancel();
176         }
177         this.pending.clear();
178         for (final E entry: this.available) {
179             entry.close();
180         }
181         this.available.clear();
182         for (final E entry: this.leased) {
183             entry.close();
184         }
185         this.leased.clear();
186     }
187 
188     @Override
189     public String toString() {
190         final StringBuilder buffer = new StringBuilder();
191         buffer.append("[route: ");
192         buffer.append(this.route);
193         buffer.append("][leased: ");
194         buffer.append(this.leased.size());
195         buffer.append("][available: ");
196         buffer.append(this.available.size());
197         buffer.append("][pending: ");
198         buffer.append(this.pending.size());
199         buffer.append("]");
200         return buffer.toString();
201     }
202 
203 }