1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 }