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      public T getRoute() {
61          return this.route;
62      }
63  
64      protected abstract E createEntry(T route, C conn);
65  
66      public int getLeasedCount() {
67          return this.leased.size();
68      }
69  
70      public int getPendingCount() {
71          return this.pending.size();
72      }
73  
74      public int getAvailableCount() {
75          return this.available.size();
76      }
77  
78      public int getAllocatedCount() {
79          return this.available.size() + this.leased.size() + this.pending.size();
80      }
81  
82      public E getFree(final Object state) {
83          if (!this.available.isEmpty()) {
84              if (state != null) {
85                  final Iterator<E> it = this.available.iterator();
86                  while (it.hasNext()) {
87                      final E entry = it.next();
88                      if (state.equals(entry.getState())) {
89                          it.remove();
90                          this.leased.add(entry);
91                          return entry;
92                      }
93                  }
94              }
95              final Iterator<E> it = this.available.iterator();
96              while (it.hasNext()) {
97                  final E entry = it.next();
98                  if (entry.getState() == null) {
99                      it.remove();
100                     this.leased.add(entry);
101                     return entry;
102                 }
103             }
104         }
105         return null;
106     }
107 
108     public E getLastUsed() {
109         if (!this.available.isEmpty()) {
110             return this.available.getLast();
111         } else {
112             return null;
113         }
114     }
115 
116     public boolean remove(final E entry) {
117         Args.notNull(entry, "Pool entry");
118         if (!this.available.remove(entry)) {
119             if (!this.leased.remove(entry)) {
120                 return false;
121             }
122         }
123         return true;
124     }
125 
126     public void free(final E entry, final boolean reusable) {
127         Args.notNull(entry, "Pool entry");
128         final boolean found = this.leased.remove(entry);
129         Asserts.check(found, "Entry %s has not been leased from this pool", entry);
130         if (reusable) {
131             this.available.addFirst(entry);
132         }
133     }
134 
135     public void addPending(
136             final SessionRequest sessionRequest,
137             final BasicFuture<E> future) {
138         this.pending.put(sessionRequest, future);
139     }
140 
141     private BasicFuture<E> removeRequest(final SessionRequest request) {
142         final BasicFuture<E> future = this.pending.remove(request);
143         Asserts.notNull(future, "Session request future");
144         return future;
145     }
146 
147     public E createEntry(final SessionRequest request, final C conn) {
148         final E entry = createEntry(this.route, conn);
149         this.leased.add(entry);
150         return entry;
151     }
152 
153     public void completed(final SessionRequest request, final E entry) {
154         final BasicFuture<E> future = removeRequest(request);
155         future.completed(entry);
156     }
157 
158     public void cancelled(final SessionRequest request) {
159         final BasicFuture<E> future = removeRequest(request);
160         future.cancel(true);
161     }
162 
163     public void failed(final SessionRequest request, final Exception ex) {
164         final BasicFuture<E> future = removeRequest(request);
165         future.failed(ex);
166     }
167 
168     public void timeout(final SessionRequest request) {
169         final BasicFuture<E> future = removeRequest(request);
170         future.failed(new SocketTimeoutException());
171     }
172 
173     public void shutdown() {
174         for (final SessionRequest sessionRequest: this.pending.keySet()) {
175             sessionRequest.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 }