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.pool;
28
29 import java.util.HashSet;
30 import java.util.Iterator;
31 import java.util.LinkedList;
32 import java.util.Set;
33
34 import org.apache.http.annotation.NotThreadSafe;
35
36 @NotThreadSafe
37 abstract class RouteSpecificPool<T, C, E extends PoolEntry<T, C>> {
38
39 private final T route;
40 private final Set<E> leased;
41 private final LinkedList<E> available;
42 private final LinkedList<PoolEntryFuture<E>> pending;
43
44 RouteSpecificPool(final T route) {
45 super();
46 this.route = route;
47 this.leased = new HashSet<E>();
48 this.available = new LinkedList<E>();
49 this.pending = new LinkedList<PoolEntryFuture<E>>();
50 }
51
52 protected abstract E createEntry(C conn);
53
54 public final T getRoute() {
55 return route;
56 }
57
58 public int getLeasedCount() {
59 return this.leased.size();
60 }
61
62 public int getPendingCount() {
63 return this.pending.size();
64 }
65
66 public int getAvailableCount() {
67 return this.available.size();
68 }
69
70 public int getAllocatedCount() {
71 return this.available.size() + this.leased.size();
72 }
73
74 public E getFree(final Object state) {
75 if (!this.available.isEmpty()) {
76 if (state != null) {
77 Iterator<E> it = this.available.iterator();
78 while (it.hasNext()) {
79 E entry = it.next();
80 if (state.equals(entry.getState())) {
81 it.remove();
82 this.leased.add(entry);
83 return entry;
84 }
85 }
86 }
87 Iterator<E> it = this.available.iterator();
88 while (it.hasNext()) {
89 E entry = it.next();
90 if (entry.getState() == null) {
91 it.remove();
92 this.leased.add(entry);
93 return entry;
94 }
95 }
96 }
97 return null;
98 }
99
100 public E getLastUsed() {
101 if (!this.available.isEmpty()) {
102 return this.available.getLast();
103 } else {
104 return null;
105 }
106 }
107
108 public boolean remove(final E entry) {
109 if (entry == null) {
110 throw new IllegalArgumentException("Pool entry may not be null");
111 }
112 if (!this.available.remove(entry)) {
113 if (!this.leased.remove(entry)) {
114 return false;
115 }
116 }
117 return true;
118 }
119
120 public void free(final E entry, boolean reusable) {
121 if (entry == null) {
122 throw new IllegalArgumentException("Pool entry may not be null");
123 }
124 boolean found = this.leased.remove(entry);
125 if (!found) {
126 throw new IllegalStateException("Entry " + entry +
127 " has not been leased from this pool");
128 }
129 if (reusable) {
130 this.available.addFirst(entry);
131 }
132 }
133
134 public E add(final C conn) {
135 E entry = createEntry(conn);
136 this.leased.add(entry);
137 return entry;
138 }
139
140 public void queue(final PoolEntryFuture<E> future) {
141 if (future == null) {
142 return;
143 }
144 this.pending.add(future);
145 }
146
147 public PoolEntryFuture<E> nextPending() {
148 return this.pending.poll();
149 }
150
151 public void unqueue(final PoolEntryFuture<E> future) {
152 if (future == null)
153 return;
154
155 this.pending.remove(future);
156 }
157
158 public void shutdown() {
159 for (PoolEntryFuture<E> future: this.pending) {
160 future.cancel(true);
161 }
162 this.pending.clear();
163 for (E entry: this.available) {
164 entry.close();
165 }
166 this.available.clear();
167 for (E entry: this.leased) {
168 entry.close();
169 }
170 this.leased.clear();
171 }
172
173 @Override
174 public String toString() {
175 StringBuilder buffer = new StringBuilder();
176 buffer.append("[route: ");
177 buffer.append(this.route);
178 buffer.append("][leased: ");
179 buffer.append(this.leased.size());
180 buffer.append("][available: ");
181 buffer.append(this.available.size());
182 buffer.append("][pending: ");
183 buffer.append(this.pending.size());
184 buffer.append("]");
185 return buffer.toString();
186 }
187
188 }