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 <major>.<minor>.<bugfix>) 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 }