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