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 import org.apache.http.util.Args;
36 import org.apache.http.util.Asserts;
37
38 @NotThreadSafe
39 abstract class RouteSpecificPool<T, C, E extends PoolEntry<T, C>> {
40
41 private final T route;
42 private final Set<E> leased;
43 private final LinkedList<E> available;
44 private final LinkedList<PoolEntryFuture<E>> pending;
45
46 RouteSpecificPool(final T route) {
47 super();
48 this.route = route;
49 this.leased = new HashSet<E>();
50 this.available = new LinkedList<E>();
51 this.pending = new LinkedList<PoolEntryFuture<E>>();
52 }
53
54 protected abstract E createEntry(C conn);
55
56 public final T getRoute() {
57 return route;
58 }
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();
74 }
75
76 public E getFree(final Object state) {
77 if (!this.available.isEmpty()) {
78 if (state != null) {
79 final Iterator<E> it = this.available.iterator();
80 while (it.hasNext()) {
81 final 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 final Iterator<E> it = this.available.iterator();
90 while (it.hasNext()) {
91 final 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 Args.notNull(entry, "Pool entry");
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, final boolean reusable) {
121 Args.notNull(entry, "Pool entry");
122 final boolean found = this.leased.remove(entry);
123 Asserts.check(found, "Entry %s has not been leased from this pool", entry);
124 if (reusable) {
125 this.available.addFirst(entry);
126 }
127 }
128
129 public E add(final C conn) {
130 final E entry = createEntry(conn);
131 this.leased.add(entry);
132 return entry;
133 }
134
135 public void queue(final PoolEntryFuture<E> future) {
136 if (future == null) {
137 return;
138 }
139 this.pending.add(future);
140 }
141
142 public PoolEntryFuture<E> nextPending() {
143 return this.pending.poll();
144 }
145
146 public void unqueue(final PoolEntryFuture<E> future) {
147 if (future == null) {
148 return;
149 }
150
151 this.pending.remove(future);
152 }
153
154 public void shutdown() {
155 for (final PoolEntryFuture<E> future: this.pending) {
156 future.cancel(true);
157 }
158 this.pending.clear();
159 for (final E entry: this.available) {
160 entry.close();
161 }
162 this.available.clear();
163 for (final E entry: this.leased) {
164 entry.close();
165 }
166 this.leased.clear();
167 }
168
169 @Override
170 public String toString() {
171 final StringBuilder buffer = new StringBuilder();
172 buffer.append("[route: ");
173 buffer.append(this.route);
174 buffer.append("][leased: ");
175 buffer.append(this.leased.size());
176 buffer.append("][available: ");
177 buffer.append(this.available.size());
178 buffer.append("][pending: ");
179 buffer.append(this.pending.size());
180 buffer.append("]");
181 return buffer.toString();
182 }
183
184 }