View Javadoc
1   /*
2    * #%L
3    * BuilderFactory.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;
21  
22  import java.math.BigInteger;
23  import java.util.Calendar;
24  import java.util.Collection;
25  import java.util.Date;
26  import java.util.Map;
27  import java.util.UUID;
28  import java.util.regex.Pattern;
29  
30  import com.allanbank.mongodb.bson.DocumentAssignable;
31  import com.allanbank.mongodb.bson.Element;
32  import com.allanbank.mongodb.bson.ElementAssignable;
33  import com.allanbank.mongodb.bson.builder.impl.ArrayBuilderImpl;
34  import com.allanbank.mongodb.bson.builder.impl.DocumentBuilderImpl;
35  import com.allanbank.mongodb.bson.element.ArrayElement;
36  import com.allanbank.mongodb.bson.element.BinaryElement;
37  import com.allanbank.mongodb.bson.element.BooleanElement;
38  import com.allanbank.mongodb.bson.element.DocumentElement;
39  import com.allanbank.mongodb.bson.element.DoubleElement;
40  import com.allanbank.mongodb.bson.element.IntegerElement;
41  import com.allanbank.mongodb.bson.element.LongElement;
42  import com.allanbank.mongodb.bson.element.NullElement;
43  import com.allanbank.mongodb.bson.element.ObjectId;
44  import com.allanbank.mongodb.bson.element.ObjectIdElement;
45  import com.allanbank.mongodb.bson.element.RegularExpressionElement;
46  import com.allanbank.mongodb.bson.element.StringElement;
47  import com.allanbank.mongodb.bson.element.TimestampElement;
48  import com.allanbank.mongodb.bson.element.UuidElement;
49  import com.allanbank.mongodb.bson.impl.RootDocument;
50  
51  /**
52   * Helper class for getting started with a builder. The use of this class is
53   * encouraged to avoid direct references to the builder implementations.
54   * <p>
55   * Two modes are provided by this class. The first uses the static methods
56   * {@link #d}, {@link #a}, and {@link #e} to create documents, arrays, and
57   * elements of a document respectfully. This allows for the quick construction
58   * of documents with a known structure. As an example consider the following
59   * code: <blockquote>
60   * 
61   * <pre>
62   * <code>
63   * DocumentBuilder movie = d(
64   *    e( "title", "Gone with the Wind" ),
65   *    e( "directors", a( "Victor Fleming", "George Cukor", "Sam Wood" ) ),
66   *    e( "stars", a( "Clark Gable", "Vivien Leigh", "Thomas Mitchell" ))
67   * );
68   * </code>
69   * </pre>
70   * 
71   * </blockquote>
72   * </p>
73   * <p>
74   * The above code creates a document with the following JSON
75   * structure:<blockquote>
76   * 
77   * <pre>
78   * <code>
79   * {
80   *    "title" : "Gone with the Wind",
81   *    "directors" : [ "Victor Fleming", "George Cukor", "Sam Wood" ],
82   *    "stars" : [ "Clark Gable", "Vivien Leigh", "Thomas Mitchell" ]
83   * }
84   * </code>
85   * </pre>
86   * 
87   * </blockquote>
88   * </p>
89   * <p>
90   * The second model for creating documents is to use the {@link DocumentBuilder}
91   * s and {@link ArrayBuilder}s directly to dynamically construct the documents.
92   * To create a dynamic builders call one of the {@link #start()} methods. Here
93   * is an example creating the equivalent document we saw above: <blockquote>
94   * 
95   * <pre>
96   * <code>
97   * DocumentBuilder movie = BuilderFactory.start();
98   * movie.add("title", "Gone with the Wind");
99   * 
100  * ArrayBuilder directorsArray = movie.pushArray("directors");
101  * directorsArray.add("Victor Fleming")
102  *               .add("George Cukor")
103  *               .add("Sam Wood");
104  * 
105  * ArrayBuilder starsArray = movie.pushArray("stars");
106  * starsArray.add("Clark Gable")
107  *           .add("Vivien Leigh")
108  *           .add("Thomas Mitchell");
109  * </code>
110  * </pre>
111  * 
112  * </blockquote>
113  * </p>
114  * <p>
115  * The choice between the static or dynamic builders is based on a user's
116  * preference.
117  * </p>
118  * 
119  * @api.yes This class is part of the driver's API. Public and protected members
120  *          will be deprecated for at least 1 non-bugfix release (version
121  *          numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) before being
122  *          removed or modified.
123  * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
124  */
125 public class BuilderFactory {
126 
127     /**
128      * Creates an array element containing no elements. e.g., an empty array.
129      * 
130      * @return The wrapped element.
131      * @throws IllegalArgumentException
132      *             If the {@code name} is <code>null</code>.
133      */
134     public static final ArrayElement a() throws IllegalArgumentException {
135         return new ArrayElement("");
136     }
137 
138     /**
139      * Creates an array element containing boolean elements.
140      * 
141      * @param values
142      *            The boolean value.
143      * @return The wrapped element.
144      * @throws IllegalArgumentException
145      *             If the {@code name} is <code>null</code>.
146      */
147     public static final ArrayElement a(final Boolean... values)
148             throws IllegalArgumentException {
149         final ArrayBuilder subArray = BuilderFactory.startArray();
150         for (final Boolean entry : values) {
151             if (entry != null) {
152                 subArray.add(entry.booleanValue());
153             }
154             else {
155                 subArray.addNull();
156             }
157         }
158         return new ArrayElement("", subArray.build());
159     }
160 
161     /**
162      * Creates an array element containing binary elements using sub-type zero
163      * (the default).
164      * <p>
165      * Will return a {@link NullElement} if any {@code data} is
166      * <code>null</code>.
167      * </p>
168      * 
169      * @param datas
170      *            The binary value.
171      * @return The wrapped element.
172      * @throws IllegalArgumentException
173      *             If the {@code name} is <code>null</code>.
174      */
175     public static final ArrayElement a(final byte[]... datas)
176             throws IllegalArgumentException {
177         final ArrayBuilder subArray = BuilderFactory.startArray();
178         for (final Object entry : datas) {
179             subArray.add(entry);
180         }
181         return new ArrayElement("", subArray.build());
182     }
183 
184     /**
185      * Creates an array element containing timestamp elements. The timestamp is
186      * the number of milliseconds since the Unix epoch.
187      * <p>
188      * Will return a {@link NullElement} if any {@code timestamp} is
189      * <code>null</code>.
190      * </p>
191      * 
192      * @param timestamps
193      *            The number of milliseconds since the Unix epoch.
194      * @return The wrapped element.
195      * @throws IllegalArgumentException
196      *             If the {@code name} is <code>null</code>.
197      */
198     public static final ArrayElement a(final Date... timestamps)
199             throws IllegalArgumentException {
200         final ArrayBuilder subArray = BuilderFactory.startArray();
201         for (final Object entry : timestamps) {
202             subArray.add(entry);
203         }
204         return new ArrayElement("", subArray.build());
205     }
206 
207     /**
208      * Creates an array element containing pre-constructed document elements.
209      * <p>
210      * Will return a {@link NullElement} if any {@code document} is
211      * <code>null</code>.
212      * </p>
213      * 
214      * @param documents
215      *            The document to wrap.
216      * @return The wrapped element.
217      * @throws IllegalArgumentException
218      *             If the {@code name} is <code>null</code>.
219      */
220     public static final ArrayElement a(final DocumentAssignable... documents)
221             throws IllegalArgumentException {
222         final ArrayBuilder subArray = BuilderFactory.startArray();
223         for (final Object entry : documents) {
224             subArray.add(entry);
225         }
226         return new ArrayElement("", subArray.build());
227     }
228 
229     /**
230      * Creates an array element containing double elements.
231      * 
232      * @param values
233      *            The double value.
234      * @return The wrapped element.
235      * @throws IllegalArgumentException
236      *             If the {@code name} is <code>null</code>.
237      */
238     public static final ArrayElement a(final Double... values)
239             throws IllegalArgumentException {
240         final ArrayBuilder subArray = BuilderFactory.startArray();
241         for (final Double entry : values) {
242             if (entry != null) {
243                 subArray.add(entry.doubleValue());
244             }
245             else {
246                 subArray.addNull();
247             }
248         }
249         return new ArrayElement("", subArray.build());
250     }
251 
252     /**
253      * Creates an array element containing the re-created slements.
254      * <p>
255      * Will return a {@link NullElement} if any {@code element} is
256      * <code>null</code>.
257      * </p>
258      * 
259      * @param elements
260      *            The element to add to wrap.
261      * @return The wrapped element.
262      * @throws IllegalArgumentException
263      *             If the {@code name} is <code>null</code>.
264      */
265     public static final ArrayElement a(final ElementAssignable... elements)
266             throws IllegalArgumentException {
267         final ArrayBuilder subArray = BuilderFactory.startArray();
268         for (final Object entry : elements) {
269             subArray.add(entry);
270         }
271         return new ArrayElement("", subArray.build());
272     }
273 
274     /**
275      * Creates an array element containing integer (32-bit signed) elements.
276      * 
277      * @param values
278      *            The integer value.
279      * @return The wrapped element.
280      * @throws IllegalArgumentException
281      *             If the {@code name} is <code>null</code>.
282      */
283     public static final ArrayElement a(final Integer... values)
284             throws IllegalArgumentException {
285         final ArrayBuilder subArray = BuilderFactory.startArray();
286         for (final Integer entry : values) {
287             if (entry != null) {
288                 subArray.add(entry.intValue());
289             }
290             else {
291                 subArray.addNull();
292             }
293         }
294         return new ArrayElement("", subArray.build());
295     }
296 
297     /**
298      * Creates an array element containing long (64-bit signed) elements.
299      * 
300      * @param values
301      *            The long value.
302      * @return The wrapped element.
303      * @throws IllegalArgumentException
304      *             If the {@code name} is <code>null</code>.
305      */
306     public static final ArrayElement a(final Long... values)
307             throws IllegalArgumentException {
308         final ArrayBuilder subArray = BuilderFactory.startArray();
309         for (final Long entry : values) {
310             if (entry != null) {
311                 subArray.add(entry.longValue());
312             }
313             else {
314                 subArray.addNull();
315             }
316         }
317         return new ArrayElement("", subArray.build());
318     }
319 
320     /**
321      * Creates an ArrayElement after trying to coerce the values into the best
322      * possible element type. If the coercion fails then an
323      * {@link IllegalArgumentException} is thrown.
324      * 
325      * @param values
326      *            The Object values to coerce into an element.
327      * @return The {@link ArrayElement} with the name {@code ""} and the
328      *         provided values.
329      * @throws IllegalArgumentException
330      *             If the {@code name} is <code>null</code> or the {@code value}
331      *             cannot be coerced into an element type.
332      */
333     public static final ArrayElement a(final Object... values) {
334         final ArrayBuilder subArray = BuilderFactory.startArray();
335         for (final Object entry : values) {
336             subArray.add(entry);
337         }
338         return new ArrayElement("", subArray.build());
339     }
340 
341     /**
342      * Creates an array element containing ObjectId elements.
343      * <p>
344      * Will return a {@link NullElement} if any {@code id} is <code>null</code>.
345      * </p>
346      * 
347      * @param ids
348      *            The ObjectId to wrap.
349      * @return The wrapped element.
350      * @throws IllegalArgumentException
351      *             If the {@code name} or {@code id} is <code>null</code>.
352      */
353     public static final ArrayElement a(final ObjectId... ids)
354             throws IllegalArgumentException {
355         final ArrayBuilder subArray = BuilderFactory.startArray();
356         for (final Object entry : ids) {
357             subArray.add(entry);
358         }
359         return new ArrayElement("", subArray.build());
360     }
361 
362     /**
363      * Creates an array element containing regular expression elements.
364      * <p>
365      * Will return a {@link NullElement} if any {@code pattern} is
366      * <code>null</code>.
367      * </p>
368      * 
369      * @param patterns
370      *            The pattern for the regular expression.
371      * @return The wrapped element.
372      * @throws IllegalArgumentException
373      *             If the {@code name} is <code>null</code>.
374      */
375     public static final ArrayElement a(final Pattern... patterns)
376             throws IllegalArgumentException {
377         final ArrayBuilder subArray = BuilderFactory.startArray();
378         for (final Object entry : patterns) {
379             subArray.add(entry);
380         }
381         return new ArrayElement("", subArray.build());
382     }
383 
384     /**
385      * Creates an array element containing string elements.
386      * <p>
387      * Will return a {@link NullElement} if any {@code value} is
388      * <code>null</code>.
389      * </p>
390      * 
391      * @param values
392      *            The string value.
393      * @return The wrapped element.
394      * @throws IllegalArgumentException
395      *             If the {@code name} is <code>null</code>.
396      */
397     public static final ArrayElement a(final String... values)
398             throws IllegalArgumentException {
399         final ArrayBuilder subArray = BuilderFactory.startArray();
400         for (final Object entry : values) {
401             subArray.add(entry);
402         }
403         return new ArrayElement("", subArray.build());
404     }
405 
406     /**
407      * Create an array element containing (sub-type 4) {@link UUID} elements.
408      * <p>
409      * Will return a {@link NullElement} if the {@code uuid} is
410      * <code>null</code>.
411      * </p>
412      * 
413      * @param uuids
414      *            The {@link UUID}s to wrap in an element.
415      * @return The wrapped element.
416      * @throws IllegalArgumentException
417      *             If the {@code name} is <code>null</code>.
418      */
419     public static final ArrayElement a(final UUID... uuids)
420             throws IllegalArgumentException {
421         final ArrayBuilder subArray = BuilderFactory.startArray();
422         for (final Object entry : uuids) {
423             subArray.add(entry);
424         }
425         return new ArrayElement("", subArray.build());
426     }
427 
428     /**
429      * Helper method for creating static document structures.
430      * 
431      * @param elements
432      *            The elements of the document. The elements may be created
433      *            using the {@link #e} methods.
434      * @return The document builder seeded with the specified elements.
435      */
436     public static final DocumentBuilder d(final Element... elements) {
437         return new DocumentBuilderImpl(new RootDocument(elements));
438     }
439 
440     /**
441      * Creates a boolean element.
442      * 
443      * @param name
444      *            The name of the element.
445      * @param value
446      *            The boolean value.
447      * @return The wrapped element.
448      * @throws IllegalArgumentException
449      *             If the {@code name} is <code>null</code>.
450      */
451     public static final BooleanElement e(final String name, final boolean value)
452             throws IllegalArgumentException {
453         return new BooleanElement(name, value);
454     }
455 
456     /**
457      * Creates a binary element using sub-type zero (the default).
458      * <p>
459      * Will return a {@link NullElement} if the {@code data} is
460      * <code>null</code>.
461      * </p>
462      * 
463      * @param name
464      *            The name of the element.
465      * @param data
466      *            The binary value.
467      * @return The wrapped element.
468      * @throws IllegalArgumentException
469      *             If the {@code name} is <code>null</code>.
470      */
471     public static final Element e(final String name, final byte[] data)
472             throws IllegalArgumentException {
473         if (data != null) {
474             return new BinaryElement(name, data);
475         }
476         return new NullElement(name);
477     }
478 
479     /**
480      * Creates a timestamp element. The timestamp is the number of milliseconds
481      * since the Unix epoch.
482      * <p>
483      * Will return a {@link NullElement} if the {@code timestamp} is
484      * <code>null</code>.
485      * </p>
486      * 
487      * @param name
488      *            The name of the element.
489      * @param timestamp
490      *            The number of milliseconds since the Unix epoch.
491      * @return The wrapped element.
492      * @throws IllegalArgumentException
493      *             If the {@code name} is <code>null</code>.
494      */
495     public static final Element e(final String name, final Date timestamp)
496             throws IllegalArgumentException {
497         if (timestamp != null) {
498             return new TimestampElement(name, timestamp.getTime());
499         }
500         return new NullElement(name);
501     }
502 
503     /**
504      * Creates a pre-constructed document element.
505      * <p>
506      * Will return a {@link NullElement} if the {@code document} is
507      * <code>null</code>.
508      * </p>
509      * 
510      * @param name
511      *            The name of the element.
512      * @param document
513      *            The document to wrap.
514      * @return The wrapped element.
515      * @throws IllegalArgumentException
516      *             If the {@code name} is <code>null</code>.
517      */
518     public static final Element e(final String name,
519             final DocumentAssignable document) throws IllegalArgumentException {
520         if (document != null) {
521             return new DocumentElement(name, document.asDocument());
522         }
523         return new NullElement(name);
524     }
525 
526     /**
527      * Creates a double element.
528      * 
529      * @param name
530      *            The name of the element.
531      * @param value
532      *            The double value.
533      * @return The wrapped element.
534      * @throws IllegalArgumentException
535      *             If the {@code name} is <code>null</code>.
536      */
537     public static final DoubleElement e(final String name, final double value)
538             throws IllegalArgumentException {
539         return new DoubleElement(name, value);
540     }
541 
542     /**
543      * Re-creates the Element with the name provided.
544      * <p>
545      * Will return a {@link NullElement} if the {@code element} is
546      * <code>null</code>.
547      * </p>
548      * 
549      * @param name
550      *            The name of the element.
551      * @param element
552      *            The element to add to wrap.
553      * @return The wrapped element.
554      * @throws IllegalArgumentException
555      *             If the {@code name} is <code>null</code>.
556      */
557     public static final Element e(final String name,
558             final ElementAssignable element) throws IllegalArgumentException {
559         if (element != null) {
560             return element.asElement().withName(name);
561         }
562         return new NullElement(name);
563     }
564 
565     /**
566      * Creates a integer (32-bit signed) element.
567      * 
568      * @param name
569      *            The name of the element.
570      * @param value
571      *            The integer value.
572      * @return The wrapped element.
573      * @throws IllegalArgumentException
574      *             If the {@code name} is <code>null</code>.
575      */
576     public static final IntegerElement e(final String name, final int value)
577             throws IllegalArgumentException {
578         return new IntegerElement(name, value);
579     }
580 
581     /**
582      * Creates a long (64-bit signed) element.
583      * 
584      * @param name
585      *            The name of the element.
586      * @param value
587      *            The long value.
588      * @return The wrapped element.
589      * @throws IllegalArgumentException
590      *             If the {@code name} is <code>null</code>.
591      */
592     public static final LongElement e(final String name, final long value)
593             throws IllegalArgumentException {
594         return new LongElement(name, value);
595     }
596 
597     /**
598      * Creates an element after trying to coerce the value into the best
599      * possible element type. If the coercion fails then an
600      * {@link IllegalArgumentException} is thrown.
601      * <p>
602      * This method does type inspection which can be slow. It is generally much
603      * faster to use the type specific {@link #e} methods of this class.
604      * </p>
605      * 
606      * @param name
607      *            The name of the element.
608      * @param value
609      *            The Object value to coerce into an element.
610      * @return The element with the name and value.
611      * @throws IllegalArgumentException
612      *             If the {@code name} is <code>null</code> or the {@code value}
613      *             cannot be coerced into an element type.
614      */
615     public static final Element e(final String name, final Object value) {
616         if (value == null) {
617             return new NullElement(name);
618         }
619         else if (value instanceof Boolean) {
620             return new BooleanElement(name, ((Boolean) value).booleanValue());
621         }
622         else if ((value instanceof Long) || (value instanceof BigInteger)) {
623             return new LongElement(name, ((Number) value).longValue());
624         }
625         else if ((value instanceof Double) || (value instanceof Float)) {
626             return new DoubleElement(name, ((Number) value).doubleValue());
627         }
628         else if (value instanceof Number) {
629             return new IntegerElement(name, ((Number) value).intValue());
630         }
631         else if (value instanceof byte[]) {
632             return new BinaryElement(name, (byte[]) value);
633         }
634         else if (value instanceof ObjectId) {
635             return new ObjectIdElement(name, (ObjectId) value);
636         }
637         else if (value instanceof Pattern) {
638             return new RegularExpressionElement(name, (Pattern) value);
639         }
640         else if (value instanceof String) {
641             return new StringElement(name, (String) value);
642         }
643         else if (value instanceof Date) {
644             return new TimestampElement(name, ((Date) value).getTime());
645         }
646         else if (value instanceof Calendar) {
647             return new TimestampElement(name, ((Calendar) value).getTime()
648                     .getTime());
649         }
650         else if (value instanceof UUID) {
651             return new UuidElement(name, (UUID) value);
652         }
653         else if (value instanceof DocumentAssignable) {
654             return new DocumentElement(name,
655                     ((DocumentAssignable) value).asDocument());
656         }
657         else if (value instanceof ElementAssignable) {
658             return ((ElementAssignable) value).asElement().withName(name);
659         }
660         else if (value instanceof Map) {
661             final DocumentBuilder subDoc = BuilderFactory.start();
662             for (final Map.Entry<?, ?> entry : ((Map<?, ?>) value).entrySet()) {
663                 subDoc.add(entry.getKey().toString(), entry.getValue());
664             }
665             return new DocumentElement(name, subDoc.build());
666         }
667         else if (value instanceof Collection) {
668             final ArrayBuilder subArray = BuilderFactory.startArray();
669             for (final Object entry : (Collection<?>) value) {
670                 subArray.add(entry);
671             }
672             return new ArrayElement(name, subArray.build());
673         }
674         else if (value instanceof Object[]) {
675             final ArrayBuilder subArray = BuilderFactory.startArray();
676             for (final Object entry : (Object[]) value) {
677                 subArray.add(entry);
678             }
679             return new ArrayElement(name, subArray.build());
680         }
681 
682         throw new IllegalArgumentException("Could not coerce the type '"
683                 + value.getClass().getName()
684                 + "' into a valid BSON element type.");
685     }
686 
687     /**
688      * Creates an ObjectId element.
689      * <p>
690      * Will return a {@link NullElement} if the {@code id} is <code>null</code>.
691      * </p>
692      * 
693      * @param name
694      *            The name of the element.
695      * @param id
696      *            The ObjectId to wrap.
697      * @return The wrapped element.
698      * @throws IllegalArgumentException
699      *             If the {@code name} or {@code id} is <code>null</code>.
700      */
701     public static final Element e(final String name, final ObjectId id)
702             throws IllegalArgumentException {
703         if (id != null) {
704             return new ObjectIdElement(name, id);
705         }
706         return new NullElement(name);
707     }
708 
709     /**
710      * Creates a regular expression element.
711      * <p>
712      * Will return a {@link NullElement} if the {@code pattern} is
713      * <code>null</code>.
714      * </p>
715      * 
716      * @param name
717      *            The name of the element.
718      * @param pattern
719      *            The pattern for the regular expression.
720      * @return The wrapped element.
721      * @throws IllegalArgumentException
722      *             If the {@code name} is <code>null</code>.
723      */
724     public static final Element e(final String name, final Pattern pattern)
725             throws IllegalArgumentException {
726         if (pattern != null) {
727             return new RegularExpressionElement(name, pattern);
728         }
729         return new NullElement(name);
730     }
731 
732     /**
733      * Creates a string element.
734      * <p>
735      * Will return a {@link NullElement} if the {@code value} is
736      * <code>null</code>.
737      * </p>
738      * 
739      * @param name
740      *            The name of the element.
741      * @param value
742      *            The string value.
743      * @return The wrapped element.
744      * @throws IllegalArgumentException
745      *             If the {@code name} is <code>null</code>.
746      */
747     public static final Element e(final String name, final String value)
748             throws IllegalArgumentException {
749         if (value != null) {
750             return new StringElement(name, value);
751         }
752         return new NullElement(name);
753     }
754 
755     /**
756      * Create a (sub-type 4) {@link UUID} element.
757      * <p>
758      * Will return a {@link NullElement} if the {@code uuid} is
759      * <code>null</code>.
760      * </p>
761      * 
762      * @param name
763      *            The name of the element.
764      * @param uuid
765      *            The {@link UUID} to wrap in an element.
766      * @return The wrapped element.
767      * @throws IllegalArgumentException
768      *             If the {@code name} is <code>null</code>.
769      */
770     public static final Element e(final String name, final UUID uuid)
771             throws IllegalArgumentException {
772         if (uuid != null) {
773             return new UuidElement(name, UuidElement.UUID_SUBTTYPE, uuid);
774         }
775         return new NullElement(name);
776     }
777 
778     /**
779      * Creates a new {@link DocumentBuilder}.
780      * 
781      * @return The root level document builder.
782      */
783     public static final DocumentBuilder start() {
784         return new DocumentBuilderImpl();
785     }
786 
787     /**
788      * Creates a new {@link DocumentBuilder} to append more elements to an
789      * existing document.
790      * 
791      * @param seedDocument
792      *            The document to seed the builder with. The builder will
793      *            contain the seed document elements plus any added/appended
794      *            elements.
795      * @return The root level document builder.
796      */
797     public static final DocumentBuilder start(
798             final DocumentAssignable seedDocument) {
799         return new DocumentBuilderImpl(seedDocument);
800     }
801 
802     /**
803      * Creates a new {@link DocumentBuilder} to append more elements to an
804      * existing set of documents.
805      * 
806      * @param seedDocuments
807      *            The documents to seed the builder with. The builder will
808      *            contain the seed document elements plus any added/appended
809      *            elements.
810      * @return The root level document builder.
811      */
812     public static final DocumentBuilder start(
813             final DocumentAssignable... seedDocuments) {
814         final DocumentBuilderImpl builder = new DocumentBuilderImpl();
815         for (final DocumentAssignable seedDocument : seedDocuments) {
816             for (final Element element : seedDocument.asDocument()) {
817                 builder.remove(element.getName());
818                 builder.add(element);
819             }
820         }
821         return builder;
822     }
823 
824     /**
825      * Creates a new {@link ArrayBuilder}.
826      * 
827      * @return The root level array builder.
828      */
829     public static final ArrayBuilder startArray() {
830         return new ArrayBuilderImpl();
831     }
832 
833     /**
834      * Creates a new builder factory.
835      */
836     private BuilderFactory() {
837         // Nothing to do.
838     }
839 }