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(
134             final SessionRequest sessionRequest,
135             final BasicFuture<E> future) {
136         this.pending.put(sessionRequest, future);
137     }
138 
139     private BasicFuture<E> removeRequest(final SessionRequest request) {
140         final BasicFuture<E> future = this.pending.remove(request);
141         Asserts.notNull(future, "Session request future");
142         return future;
143     }
144 
145     public E createEntry(final SessionRequest request, final C conn) {
146         final E entry = createEntry(this.route, conn);
147         this.leased.add(entry);
148         return entry;
149     }
150 
151     public void completed(final SessionRequest request, final E entry) {
152         final BasicFuture<E> future = removeRequest(request);
153         future.completed(entry);
154     }
155 
156     public void cancelled(final SessionRequest request) {
157         final BasicFuture<E> future = removeRequest(request);
158         future.cancel(true);
159     }
160 
161     public void failed(final SessionRequest request, final Exception ex) {
162         final BasicFuture<E> future = removeRequest(request);
163         future.failed(ex);
164     }
165 
166     public void timeout(final SessionRequest request) {
167         final BasicFuture<E> future = removeRequest(request);
168         future.failed(new ConnectException());
169     }
170 
171     public void shutdown() {
172         for (final SessionRequest sessionRequest: this.pending.keySet()) {
173             sessionRequest.cancel();
174         }
175         this.pending.clear();
176         for (final E entry: this.available) {
177             entry.close();
178         }
179         this.available.clear();
180         for (final E entry: this.leased) {
181             entry.close();
182         }
183         this.leased.clear();
184     }
185 
186     @Override
187     public String toString() {
188         final StringBuilder buffer = new StringBuilder();
189         buffer.append("[route: ");
190         buffer.append(this.route);
191         buffer.append("][leased: ");
192         buffer.append(this.leased.size());
193         buffer.append("][available: ");
194         buffer.append(this.available.size());
195         buffer.append("][pending: ");
196         buffer.append(this.pending.size());
197         buffer.append("]");
198         return buffer.toString();
199     }
200 
201 }