1 package com.trendmicro.grid.acl.l0;
2
3 import com.trendmicro.grid.acl.Limits;
4
5 import java.io.Serializable;
6 import java.util.*;
7
8 import static com.trendmicro.grid.acl.Limits.MAX_INCOMING_REQUEST_BATCH_SIZE;
9 import static net.sf.tinyjee.util.Assert.assertNotNull;
10
11
12
13
14
15
16
17 public class BatchCollection<E> extends AbstractCollection<E> implements Serializable {
18
19 private static final long serialVersionUID = 1600249921512556499L;
20
21
22
23
24
25
26
27 public interface Invoker<E, R> {
28
29
30
31
32
33
34
35 public R invoke(BatchCollection<E> chunk) throws WebException;
36 }
37
38
39
40
41
42
43
44 public static <E> BatchCollection<E> of(E element) {
45 return new BatchCollection<E>(element);
46 }
47
48
49
50
51
52
53
54
55 public static <E> BatchCollection<E> of(E... elements) {
56 return of(Arrays.asList(elements));
57 }
58
59
60
61
62
63
64
65
66 public static <E> BatchCollection<E> of(Collection<? extends E> elements) {
67 return new BatchCollection<E>(elements);
68 }
69
70
71
72
73
74
75
76 public static <E> List<BatchCollection<E>> chunksOf(List<? extends E> elements) {
77 return chunksOf(elements, MAX_INCOMING_REQUEST_BATCH_SIZE);
78 }
79
80
81
82
83
84
85
86
87 public static <E> List<BatchCollection<E>> chunksOf(List<? extends E> elements, int batchSize) {
88 final List<BatchCollection<E>> collections = new ArrayList<BatchCollection<E>>();
89 for (int i = 0, length = elements.size(); i < length; i += batchSize) {
90 List<? extends E> chunk = elements.subList(i, Math.min(i + batchSize, length));
91 collections.add(new BatchCollection<E>(chunk, batchSize));
92 }
93 return collections;
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 @SuppressWarnings("unchecked")
122 public static <E, R, T extends Collection<R>> T invokeOnChunksOf(
123 Collection<? extends E> elements, Invoker<E, T> invoker) throws WebException {
124
125 T result = null;
126 final List<? extends E> listOfElements = elements instanceof List ?
127 (List<? extends E>) elements : new ArrayList<E>(elements);
128
129 while (true) {
130 try {
131 for (BatchCollection<E> currentChunk : chunksOf(listOfElements, defaultInvocationBatchSize)) {
132 Collection<R> r = invoker.invoke(currentChunk);
133 if (r != null) {
134 if (result == null)
135 result = (T) r;
136 else
137 result.addAll(r);
138 }
139 }
140 break;
141 } catch (BatchSizeExceededException e) {
142 defaultInvocationBatchSize = e.getAllowedBatchSize();
143 }
144 }
145
146 return result;
147 }
148
149 private static int defaultInvocationBatchSize = MAX_INCOMING_REQUEST_BATCH_SIZE;
150
151
152
153
154
155
156 public static int getDefaultInvocationBatchSize() {
157 return defaultInvocationBatchSize;
158 }
159
160
161
162
163
164
165
166 public static void setDefaultInvocationBatchSize(int defaultInvocationBatchSize) {
167 BatchCollection.defaultInvocationBatchSize = defaultInvocationBatchSize;
168 }
169
170 private int batchSize;
171 private Collection<E> backingStore;
172
173
174
175
176 public BatchCollection() {
177 this(MAX_INCOMING_REQUEST_BATCH_SIZE);
178 }
179
180
181
182
183
184
185 public BatchCollection(int batchSize) {
186 this.batchSize = batchSize;
187 backingStore = new LinkedList<E>();
188 }
189
190 BatchCollection(Collection<? extends E> elements) {
191 this(elements, MAX_INCOMING_REQUEST_BATCH_SIZE);
192 }
193
194 BatchCollection(Collection<? extends E> elements, int batchSize) {
195 assertNotNull("elements", elements);
196
197 this.batchSize = batchSize;
198 assertIsWithinLimit(elements.size());
199 backingStore = Collections.unmodifiableCollection(elements);
200 }
201
202 BatchCollection(E singleElement) {
203 assertNotNull("singleElement", singleElement);
204 backingStore = Collections.singleton(singleElement);
205 }
206
207 private void assertIsWithinLimit(int elementCountToAdd) {
208 int size = backingStore == null ? 0 : backingStore.size();
209 if (size + elementCountToAdd > batchSize)
210 throw new BatchSizeExceededException(batchSize);
211 }
212
213
214
215
216
217 @Override
218 public boolean add(E e) {
219 assertIsWithinLimit(1);
220 return backingStore.add(e);
221 }
222
223
224
225
226 @Override
227 public boolean addAll(Collection<? extends E> c) {
228 assertIsWithinLimit(c.size());
229 return backingStore.addAll(c);
230 }
231
232
233
234
235 @Override
236 public Iterator<E> iterator() {
237 return backingStore.iterator();
238 }
239
240
241
242
243 @Override
244 public int size() {
245 return backingStore.size();
246 }
247
248
249
250
251 @Override
252 public boolean isEmpty() {
253 return backingStore.isEmpty();
254 }
255
256
257
258
259 @Override
260 public boolean contains(Object o) {
261 return backingStore.contains(o);
262 }
263
264
265
266
267 @Override
268 public Object[] toArray() {
269 return backingStore.toArray();
270 }
271
272
273
274
275 @Override
276 public <T> T[] toArray(T[] a) {
277 return backingStore.toArray(a);
278 }
279
280
281
282
283 @Override
284 public boolean containsAll(Collection<?> c) {
285 return backingStore.containsAll(c);
286 }
287
288
289
290
291 @Override
292 public boolean equals(Object o) {
293 if (this == o) return true;
294 if (o == null || getClass() != o.getClass()) return false;
295 BatchCollection that = (BatchCollection) o;
296 return backingStore.equals(that.backingStore);
297 }
298
299
300
301
302 @Override
303 public int hashCode() {
304 return backingStore.hashCode();
305 }
306 }