View Javadoc
1   /*
2    * #%L
3    * DocumentBuilderImpl.java - mongodb-async-driver - Allanbank Consulting, Inc.
4    * %%
5    * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.allanbank.mongodb.bson.builder.impl;
21  
22  import java.io.StringWriter;
23  import java.util.Date;
24  import java.util.Iterator;
25  import java.util.UUID;
26  import java.util.regex.Pattern;
27  
28  import com.allanbank.mongodb.bson.Document;
29  import com.allanbank.mongodb.bson.DocumentAssignable;
30  import com.allanbank.mongodb.bson.Element;
31  import com.allanbank.mongodb.bson.ElementAssignable;
32  import com.allanbank.mongodb.bson.builder.ArrayBuilder;
33  import com.allanbank.mongodb.bson.builder.BuilderFactory;
34  import com.allanbank.mongodb.bson.builder.DocumentBuilder;
35  import com.allanbank.mongodb.bson.element.BinaryElement;
36  import com.allanbank.mongodb.bson.element.BooleanElement;
37  import com.allanbank.mongodb.bson.element.DocumentElement;
38  import com.allanbank.mongodb.bson.element.DoubleElement;
39  import com.allanbank.mongodb.bson.element.IntegerElement;
40  import com.allanbank.mongodb.bson.element.JavaScriptElement;
41  import com.allanbank.mongodb.bson.element.JavaScriptWithScopeElement;
42  import com.allanbank.mongodb.bson.element.JsonSerializationVisitor;
43  import com.allanbank.mongodb.bson.element.LongElement;
44  import com.allanbank.mongodb.bson.element.MaxKeyElement;
45  import com.allanbank.mongodb.bson.element.MinKeyElement;
46  import com.allanbank.mongodb.bson.element.MongoTimestampElement;
47  import com.allanbank.mongodb.bson.element.NullElement;
48  import com.allanbank.mongodb.bson.element.ObjectId;
49  import com.allanbank.mongodb.bson.element.ObjectIdElement;
50  import com.allanbank.mongodb.bson.element.RegularExpressionElement;
51  import com.allanbank.mongodb.bson.element.StringElement;
52  import com.allanbank.mongodb.bson.element.SymbolElement;
53  import com.allanbank.mongodb.bson.element.TimestampElement;
54  import com.allanbank.mongodb.bson.element.UuidElement;
55  import com.allanbank.mongodb.bson.impl.RootDocument;
56  
57  /**
58   * A builder for BSON documents.
59   * 
60   * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
61   *         mutated in incompatible ways between any two releases of the driver.
62   * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
63   */
64  public class DocumentBuilderImpl extends AbstractBuilder implements
65          DocumentBuilder {
66  
67      /** Tracks if an _id element is present. */
68      private boolean myIdPresent;
69  
70      /**
71       * Creates a new builder.
72       */
73      public DocumentBuilderImpl() {
74          this((AbstractBuilder) null);
75      }
76  
77      /**
78       * Creates a new builder.
79       * 
80       * @param outerScope
81       *            The outer document scope.
82       */
83      public DocumentBuilderImpl(final AbstractBuilder outerScope) {
84          super(outerScope);
85      }
86  
87      /**
88       * Creates a new builder.
89       * 
90       * @param seedDocument
91       *            The document to seed the builder with. The builder will
92       *            contain the seed document elements plus any added/appended
93       *            elements.
94       */
95      public DocumentBuilderImpl(final DocumentAssignable seedDocument) {
96          this((AbstractBuilder) null);
97  
98          final Document document = seedDocument.asDocument();
99          myElements.addAll(document.getElements());
100     }
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
106     public DocumentBuilder add(final ElementAssignable elementRef)
107             throws IllegalArgumentException {
108         final Element element = elementRef.asElement();
109         myElements.add(element);
110         if ("_id".equals(element.getName())) {
111             myIdPresent = true;
112         }
113         return this;
114     }
115 
116     /**
117      * {@inheritDoc}
118      */
119     @Override
120     public DocumentBuilder add(final String name, final boolean value)
121             throws IllegalArgumentException {
122         return addBoolean(name, value);
123     }
124 
125     /**
126      * {@inheritDoc}
127      */
128     @Override
129     public DocumentBuilder add(final String name, final byte subType,
130             final byte[] data) throws IllegalArgumentException {
131         return addBinary(name, subType, data);
132     }
133 
134     /**
135      * {@inheritDoc}
136      */
137     @Override
138     public DocumentBuilder add(final String name, final byte[] data)
139             throws IllegalArgumentException {
140         if (data == null) {
141             return addNull(name);
142         }
143         return addBinary(name, data);
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     @Override
150     public DocumentBuilder add(final String name, final Date timestamp)
151             throws IllegalArgumentException {
152         if (timestamp == null) {
153             return addNull(name);
154         }
155         return addTimestamp(name, timestamp.getTime());
156     }
157 
158     /**
159      * {@inheritDoc}
160      */
161     @Override
162     public DocumentBuilder add(final String name,
163             final DocumentAssignable document) throws IllegalArgumentException {
164         if (document == null) {
165             return addNull(name);
166         }
167         return addDocument(name, document);
168     }
169 
170     /**
171      * {@inheritDoc}
172      */
173     @Override
174     public DocumentBuilder add(final String name, final double value)
175             throws IllegalArgumentException {
176         return addDouble(name, value);
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     @Override
183     public DocumentBuilder add(final String name, final int value)
184             throws IllegalArgumentException {
185         return addInteger(name, value);
186     }
187 
188     /**
189      * {@inheritDoc}
190      */
191     @Override
192     public DocumentBuilder add(final String name, final long value)
193             throws IllegalArgumentException {
194         return addLong(name, value);
195     }
196 
197     /**
198      * {@inheritDoc}
199      */
200     @Override
201     public DocumentBuilder add(final String name, final Object value)
202             throws IllegalArgumentException {
203         add(BuilderFactory.e(name, value));
204         return this;
205     }
206 
207     /**
208      * {@inheritDoc}
209      */
210     @Override
211     public DocumentBuilder add(final String name, final ObjectId id)
212             throws IllegalArgumentException {
213         if (id == null) {
214             return addNull(name);
215         }
216         return addObjectId(name, id);
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
223     public DocumentBuilder add(final String name, final Pattern pattern)
224             throws IllegalArgumentException {
225         if (pattern == null) {
226             return addNull(name);
227         }
228         return addRegularExpression(name, pattern);
229     }
230 
231     /**
232      * {@inheritDoc}
233      */
234     @Override
235     public DocumentBuilder add(final String name, final String value)
236             throws IllegalArgumentException {
237         if (value == null) {
238             return addNull(name);
239         }
240         return addString(name, value);
241     }
242 
243     /**
244      * {@inheritDoc}
245      */
246     @Override
247     @Deprecated
248     public DocumentBuilder add(final String name, final String databaseName,
249             final String collectionName, final ObjectId id)
250             throws IllegalArgumentException {
251         return addDBPointer(name, databaseName, collectionName, id);
252     }
253 
254     /**
255      * {@inheritDoc}
256      */
257     @Override
258     public DocumentBuilder add(final String name, final UUID uuid)
259             throws IllegalArgumentException {
260         if (uuid == null) {
261             return addNull(name);
262         }
263         return addUuid(name, uuid);
264     }
265 
266     /**
267      * {@inheritDoc}
268      */
269     @Override
270     public DocumentBuilder addBinary(final String name, final byte subType,
271             final byte[] value) throws IllegalArgumentException {
272         return add(new BinaryElement(name, subType, value));
273     }
274 
275     /**
276      * {@inheritDoc}
277      */
278     @Override
279     public DocumentBuilder addBinary(final String name, final byte[] value)
280             throws IllegalArgumentException {
281         return add(new BinaryElement(name, value));
282     }
283 
284     /**
285      * {@inheritDoc}
286      */
287     @Override
288     public DocumentBuilder addBoolean(final String name, final boolean value)
289             throws IllegalArgumentException {
290         return add(new BooleanElement(name, value));
291     }
292 
293     /**
294      * {@inheritDoc}
295      */
296     @Override
297     @Deprecated
298     public DocumentBuilder addDBPointer(final String name,
299             final String databaseName, final String collectionName,
300             final ObjectId id) throws IllegalArgumentException {
301         return add(new com.allanbank.mongodb.bson.element.DBPointerElement(
302                 name, databaseName, collectionName, id));
303     }
304 
305     /**
306      * {@inheritDoc}
307      */
308     @Override
309     public DocumentBuilder addDocument(final String name,
310             final DocumentAssignable value) throws IllegalArgumentException {
311         return add(new DocumentElement(name, value.asDocument()));
312     }
313 
314     /**
315      * {@inheritDoc}
316      */
317     @Override
318     public DocumentBuilder addDouble(final String name, final double value)
319             throws IllegalArgumentException {
320         return add(new DoubleElement(name, value));
321     }
322 
323     /**
324      * {@inheritDoc}
325      */
326     @Override
327     public DocumentBuilder addInteger(final String name, final int value)
328             throws IllegalArgumentException {
329         return add(new IntegerElement(name, value));
330     }
331 
332     /**
333      * {@inheritDoc}
334      */
335     @Override
336     public DocumentBuilder addJavaScript(final String name, final String code)
337             throws IllegalArgumentException {
338         return add(new JavaScriptElement(name, code));
339     }
340 
341     /**
342      * {@inheritDoc}
343      */
344     @Override
345     public DocumentBuilder addJavaScript(final String name, final String code,
346             final DocumentAssignable scope) throws IllegalArgumentException {
347         return add(new JavaScriptWithScopeElement(name, code,
348                 scope.asDocument()));
349     }
350 
351     /**
352      * {@inheritDoc}
353      */
354     @Override
355     public DocumentBuilder addLegacyUuid(final String name, final UUID uuid)
356             throws IllegalArgumentException {
357         return add(new UuidElement(name, UuidElement.LEGACY_UUID_SUBTTYPE, uuid));
358     }
359 
360     /**
361      * {@inheritDoc}
362      */
363     @Override
364     public DocumentBuilder addLong(final String name, final long value)
365             throws IllegalArgumentException {
366         return add(new LongElement(name, value));
367     }
368 
369     /**
370      * {@inheritDoc}
371      */
372     @Override
373     public DocumentBuilder addMaxKey(final String name)
374             throws IllegalArgumentException {
375         return add(new MaxKeyElement(name));
376     }
377 
378     /**
379      * {@inheritDoc}
380      */
381     @Override
382     public DocumentBuilder addMinKey(final String name)
383             throws IllegalArgumentException {
384         return add(new MinKeyElement(name));
385     }
386 
387     /**
388      * {@inheritDoc}
389      */
390     @Override
391     public DocumentBuilder addMongoTimestamp(final String name, final long value)
392             throws IllegalArgumentException {
393         return add(new MongoTimestampElement(name, value));
394     }
395 
396     /**
397      * {@inheritDoc}
398      */
399     @Override
400     public DocumentBuilder addNull(final String name)
401             throws IllegalArgumentException {
402         return add(new NullElement(name));
403     }
404 
405     /**
406      * {@inheritDoc}
407      */
408     @Override
409     public DocumentBuilder addObjectId(final String name, final ObjectId id)
410             throws IllegalArgumentException {
411         return add(new ObjectIdElement(name, id));
412     }
413 
414     /**
415      * {@inheritDoc}
416      */
417     @Override
418     public DocumentBuilder addRegularExpression(final String name,
419             final Pattern pattern) throws IllegalArgumentException {
420         return add(new RegularExpressionElement(name, pattern));
421     }
422 
423     /**
424      * {@inheritDoc}
425      */
426     @Override
427     public DocumentBuilder addRegularExpression(final String name,
428             final String pattern, final String options)
429             throws IllegalArgumentException {
430         return add(new RegularExpressionElement(name, pattern, options));
431     }
432 
433     /**
434      * {@inheritDoc}
435      */
436     @Override
437     public DocumentBuilder addString(final String name, final String value)
438             throws IllegalArgumentException {
439         return add(new StringElement(name, value));
440     }
441 
442     /**
443      * {@inheritDoc}
444      */
445     @Override
446     public DocumentBuilder addSymbol(final String name, final String symbol)
447             throws IllegalArgumentException {
448         return add(new SymbolElement(name, symbol));
449     }
450 
451     /**
452      * {@inheritDoc}
453      */
454     @Override
455     public DocumentBuilder addTimestamp(final String name, final long timestamp)
456             throws IllegalArgumentException {
457         return add(new TimestampElement(name, timestamp));
458     }
459 
460     /**
461      * {@inheritDoc}
462      */
463     @Override
464     public DocumentBuilder addUuid(final String name, final UUID uuid)
465             throws IllegalArgumentException {
466         return add(new UuidElement(name, UuidElement.UUID_SUBTTYPE, uuid));
467     }
468 
469     /**
470      * {@inheritDoc}
471      * <p>
472      * Returns the result of {@link #build()}.
473      * </p>
474      * 
475      * @see #build()
476      */
477     @Override
478     public Document asDocument() {
479         return build();
480     }
481 
482     /**
483      * {@inheritDoc}
484      */
485     @Override
486     public Document build() {
487         return new RootDocument(subElements(), myIdPresent);
488     }
489 
490     /**
491      * {@inheritDoc}
492      */
493     @Override
494     public DocumentBuilder push(final String name) {
495         return doPush(name);
496     }
497 
498     /**
499      * {@inheritDoc}
500      */
501     @Override
502     public ArrayBuilder pushArray(final String name) {
503         return doPushArray(name);
504     }
505 
506     /**
507      * {@inheritDoc}
508      */
509     @Override
510     public DocumentBuilder remove(final String name) {
511         final Iterator<Element> iter = myElements.iterator();
512         while (iter.hasNext()) {
513             if (name.equals(iter.next().getName())) {
514                 iter.remove();
515             }
516         }
517         return this;
518     }
519 
520     /**
521      * {@inheritDoc}
522      */
523     @Override
524     public DocumentBuilder reset() {
525         super.reset();
526         return this;
527     }
528 
529     /**
530      * {@inheritDoc}
531      * <p>
532      * Overridden to return the current state of the builder as a document.
533      * </p>
534      */
535     @Override
536     public String toString() {
537         final StringWriter writer = new StringWriter();
538         final JsonSerializationVisitor visitor = new JsonSerializationVisitor(
539                 writer, false);
540 
541         visitor.visit(myElements);
542 
543         return writer.toString();
544     }
545 
546     /**
547      * {@inheritDoc}
548      * <p>
549      * Overridden to return an {@link DocumentElement}.
550      * </p>
551      */
552     @Override
553     protected Element build(final String name) {
554         return new DocumentElement(name, subElements(), true);
555     }
556 }