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
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 }