1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.allanbank.mongodb.bson.element;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.regex.Pattern;
28 import java.util.regex.PatternSyntaxException;
29
30 import com.allanbank.mongodb.bson.Element;
31 import com.allanbank.mongodb.bson.ElementType;
32 import com.allanbank.mongodb.bson.Visitor;
33 import com.allanbank.mongodb.bson.io.StringEncoder;
34 import com.allanbank.mongodb.util.PatternUtils;
35
36
37
38
39
40
41
42
43
44
45 public class ArrayElement extends AbstractElement {
46
47
48 public static final ElementType TYPE = ElementType.ARRAY;
49
50
51 private static final String[] ourIndexes;
52
53
54 private static final long serialVersionUID = -7363294574214059703L;
55 static {
56 ourIndexes = new String[1000];
57
58 for (int i = 0; i < ourIndexes.length; ++i) {
59 ourIndexes[i] = Integer.toString(i).intern();
60 }
61 }
62
63
64
65
66
67
68
69
70
71 public static final String nameFor(final int index) {
72 if ((0 <= index) && (index < ourIndexes.length)) {
73 return ourIndexes[index];
74 }
75 return Integer.toString(index);
76 }
77
78
79
80
81
82
83
84
85
86
87
88 private static long computeSize(final String name,
89 final List<Element> entries) {
90 long result = 7;
91
92 result += StringEncoder.utf8Size(name);
93 if ((entries != null) && !entries.isEmpty()) {
94 for (final Element element : entries) {
95 result += element.size();
96 }
97 }
98
99 return result;
100 }
101
102
103
104
105
106 private final List<Element> myEntries;
107
108
109
110
111
112
113
114
115
116
117
118 public ArrayElement(final String name, final Element... entries)
119 throws IllegalArgumentException {
120 this(name, Arrays.asList(entries));
121 }
122
123
124
125
126
127
128
129
130
131
132
133 public ArrayElement(final String name, final List<Element> entries)
134 throws IllegalArgumentException {
135 this(name, entries, computeSize(name, entries));
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 public ArrayElement(final String name, final List<Element> entries,
153 final long size) throws IllegalArgumentException {
154 super(name, size);
155
156 if ((entries != null) && !entries.isEmpty()) {
157
158 final int length = entries.size();
159 final List<Element> elements = new ArrayList<Element>(length);
160 int index = 0;
161 for (final Element element : entries) {
162 final Element withCorrectName = element
163 .withName(nameFor(index));
164 elements.add(withCorrectName);
165 index += 1;
166 }
167
168 myEntries = Collections.unmodifiableList(elements);
169 }
170 else {
171 myEntries = Collections.emptyList();
172 }
173 }
174
175
176
177
178
179
180
181 @Override
182 public void accept(final Visitor visitor) {
183 if (visitor instanceof SizeAwareVisitor) {
184 ((SizeAwareVisitor) visitor).visitArray(getName(), getEntries(),
185 size());
186 }
187 else {
188 visitor.visitArray(getName(), getEntries());
189 }
190 }
191
192
193
194
195
196
197
198
199 @Override
200 public int compareTo(final Element otherElement) {
201 int result = super.compareTo(otherElement);
202
203 if (result == 0) {
204 final ArrayElement other = (ArrayElement) otherElement;
205 final int length = Math.min(myEntries.size(),
206 other.myEntries.size());
207 for (int i = 0; i < length; ++i) {
208 result = myEntries.get(i).compareTo(other.myEntries.get(i));
209 if (result != 0) {
210 return result;
211 }
212 }
213
214 result = myEntries.size() - other.myEntries.size();
215 }
216
217 return result;
218 }
219
220
221
222
223
224
225
226
227
228
229 @Override
230 public boolean equals(final Object object) {
231 boolean result = false;
232 if (this == object) {
233 result = true;
234 }
235 else if ((object != null) && (getClass() == object.getClass())) {
236 final ArrayElement other = (ArrayElement) object;
237
238 result = super.equals(object) && myEntries.equals(other.myEntries);
239 }
240 return result;
241 }
242
243
244
245
246
247
248
249
250
251
252 @Override
253 public <E extends Element> List<E> find(final Class<E> clazz,
254 final String... nameRegexs) {
255 if (0 < nameRegexs.length) {
256 final List<E> elements = new ArrayList<E>();
257 final String nameRegex = nameRegexs[0];
258 final String[] subNameRegexs = Arrays.copyOfRange(nameRegexs, 1,
259 nameRegexs.length);
260 try {
261 final Pattern pattern = PatternUtils.toPattern(nameRegex);
262 for (final Element element : myEntries) {
263 if (pattern.matcher(element.getName()).matches()) {
264 elements.addAll(element.find(clazz, subNameRegexs));
265 }
266 }
267 }
268 catch (final PatternSyntaxException pse) {
269
270 for (final Element element : myEntries) {
271 if (nameRegex.equals(element.getName())) {
272 elements.addAll(element.find(clazz, subNameRegexs));
273 }
274 }
275 }
276
277 return elements;
278 }
279
280
281 if (clazz.isAssignableFrom(this.getClass())) {
282 return Collections.singletonList(clazz.cast(this));
283 }
284 return Collections.emptyList();
285 }
286
287
288
289
290
291
292
293
294
295
296 @Override
297 public <E extends Element> E findFirst(final Class<E> clazz,
298 final String... nameRegexs) {
299 E element = null;
300 if (0 < nameRegexs.length) {
301 final String nameRegex = nameRegexs[0];
302 final String[] subNameRegexs = Arrays.copyOfRange(nameRegexs, 1,
303 nameRegexs.length);
304
305 try {
306 final Pattern pattern = PatternUtils.toPattern(nameRegex);
307 final Iterator<Element> iter = myEntries.iterator();
308 while (iter.hasNext() && (element == null)) {
309 final Element docElement = iter.next();
310 if (pattern.matcher(docElement.getName()).matches()) {
311 element = docElement.findFirst(clazz, subNameRegexs);
312 }
313 }
314 }
315 catch (final PatternSyntaxException pse) {
316
317 final Iterator<Element> iter = myEntries.iterator();
318 while (iter.hasNext() && (element == null)) {
319 final Element docElement = iter.next();
320 if (nameRegex.equals(docElement.getName())) {
321 element = docElement.findFirst(clazz, subNameRegexs);
322 }
323 }
324 }
325 }
326 else {
327
328 if (clazz.isAssignableFrom(this.getClass())) {
329 element = clazz.cast(this);
330 }
331 }
332 return element;
333 }
334
335
336
337
338
339
340
341
342 public List<Element> getEntries() {
343 return myEntries;
344 }
345
346
347
348
349 @Override
350 public ElementType getType() {
351 return TYPE;
352 }
353
354
355
356
357
358
359
360 @Override
361 public Element[] getValueAsObject() {
362 return myEntries.toArray(new Element[myEntries.size()]);
363 }
364
365
366
367
368
369
370 @Override
371 public int hashCode() {
372 int result = 1;
373 result = (31 * result) + super.hashCode();
374 result = (31 * result) + myEntries.hashCode();
375 return result;
376 }
377
378
379
380
381
382
383
384 @Override
385 public ArrayElement withName(final String name) {
386 if (getName().equals(name)) {
387 return this;
388 }
389 return new ArrayElement(name, myEntries);
390 }
391
392 }