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