Coverage Report - com.allanbank.mongodb.bson.builder.BuilderFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
BuilderFactory
95%
141/148
95%
94/98
3.273
 
 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  0
         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  4
         final ArrayBuilder subArray = BuilderFactory.startArray();
 150  12
         for (final Boolean entry : values) {
 151  8
             if (entry != null) {
 152  8
                 subArray.add(entry.booleanValue());
 153  
             }
 154  
             else {
 155  0
                 subArray.addNull();
 156  
             }
 157  
         }
 158  4
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 178  3
         for (final Object entry : datas) {
 179  2
             subArray.add(entry);
 180  
         }
 181  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 201  3
         for (final Object entry : timestamps) {
 202  2
             subArray.add(entry);
 203  
         }
 204  1
         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  48
         final ArrayBuilder subArray = BuilderFactory.startArray();
 223  141
         for (final Object entry : documents) {
 224  93
             subArray.add(entry);
 225  
         }
 226  48
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 241  3
         for (final Double entry : values) {
 242  2
             if (entry != null) {
 243  2
                 subArray.add(entry.doubleValue());
 244  
             }
 245  
             else {
 246  0
                 subArray.addNull();
 247  
             }
 248  
         }
 249  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 268  3
         for (final Object entry : elements) {
 269  2
             subArray.add(entry);
 270  
         }
 271  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 286  5
         for (final Integer entry : values) {
 287  4
             if (entry != null) {
 288  4
                 subArray.add(entry.intValue());
 289  
             }
 290  
             else {
 291  0
                 subArray.addNull();
 292  
             }
 293  
         }
 294  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 309  5
         for (final Long entry : values) {
 310  4
             if (entry != null) {
 311  4
                 subArray.add(entry.longValue());
 312  
             }
 313  
             else {
 314  0
                 subArray.addNull();
 315  
             }
 316  
         }
 317  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 335  5
         for (final Object entry : values) {
 336  4
             subArray.add(entry);
 337  
         }
 338  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 356  3
         for (final Object entry : ids) {
 357  2
             subArray.add(entry);
 358  
         }
 359  1
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 378  3
         for (final Object entry : patterns) {
 379  2
             subArray.add(entry);
 380  
         }
 381  1
         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  14
         final ArrayBuilder subArray = BuilderFactory.startArray();
 400  50
         for (final Object entry : values) {
 401  36
             subArray.add(entry);
 402  
         }
 403  14
         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  1
         final ArrayBuilder subArray = BuilderFactory.startArray();
 422  3
         for (final Object entry : uuids) {
 423  2
             subArray.add(entry);
 424  
         }
 425  1
         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  100274
         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  72
         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  2
         if (data != null) {
 474  1
             return new BinaryElement(name, data);
 475  
         }
 476  1
         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  2
         if (timestamp != null) {
 498  1
             return new TimestampElement(name, timestamp.getTime());
 499  
         }
 500  1
         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  152
         if (document != null) {
 521  151
             return new DocumentElement(name, document.asDocument());
 522  
         }
 523  1
         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  1
         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  51
         if (element != null) {
 560  50
             return element.asElement().withName(name);
 561  
         }
 562  1
         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  106
         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  1
         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  195
         if (value == null) {
 617  3
             return new NullElement(name);
 618  
         }
 619  192
         else if (value instanceof Boolean) {
 620  2
             return new BooleanElement(name, ((Boolean) value).booleanValue());
 621  
         }
 622  190
         else if ((value instanceof Long) || (value instanceof BigInteger)) {
 623  5
             return new LongElement(name, ((Number) value).longValue());
 624  
         }
 625  185
         else if ((value instanceof Double) || (value instanceof Float)) {
 626  8
             return new DoubleElement(name, ((Number) value).doubleValue());
 627  
         }
 628  177
         else if (value instanceof Number) {
 629  3
             return new IntegerElement(name, ((Number) value).intValue());
 630  
         }
 631  174
         else if (value instanceof byte[]) {
 632  4
             return new BinaryElement(name, (byte[]) value);
 633  
         }
 634  170
         else if (value instanceof ObjectId) {
 635  4
             return new ObjectIdElement(name, (ObjectId) value);
 636  
         }
 637  166
         else if (value instanceof Pattern) {
 638  4
             return new RegularExpressionElement(name, (Pattern) value);
 639  
         }
 640  162
         else if (value instanceof String) {
 641  46
             return new StringElement(name, (String) value);
 642  
         }
 643  116
         else if (value instanceof Date) {
 644  4
             return new TimestampElement(name, ((Date) value).getTime());
 645  
         }
 646  112
         else if (value instanceof Calendar) {
 647  2
             return new TimestampElement(name, ((Calendar) value).getTime()
 648  
                     .getTime());
 649  
         }
 650  110
         else if (value instanceof UUID) {
 651  4
             return new UuidElement(name, (UUID) value);
 652  
         }
 653  106
         else if (value instanceof DocumentAssignable) {
 654  95
             return new DocumentElement(name,
 655  
                     ((DocumentAssignable) value).asDocument());
 656  
         }
 657  11
         else if (value instanceof ElementAssignable) {
 658  3
             return ((ElementAssignable) value).asElement().withName(name);
 659  
         }
 660  8
         else if (value instanceof Map) {
 661  2
             final DocumentBuilder subDoc = BuilderFactory.start();
 662  2
             for (final Map.Entry<?, ?> entry : ((Map<?, ?>) value).entrySet()) {
 663  2
                 subDoc.add(entry.getKey().toString(), entry.getValue());
 664  2
             }
 665  2
             return new DocumentElement(name, subDoc.build());
 666  
         }
 667  6
         else if (value instanceof Collection) {
 668  2
             final ArrayBuilder subArray = BuilderFactory.startArray();
 669  2
             for (final Object entry : (Collection<?>) value) {
 670  2
                 subArray.add(entry);
 671  2
             }
 672  2
             return new ArrayElement(name, subArray.build());
 673  
         }
 674  4
         else if (value instanceof Object[]) {
 675  2
             final ArrayBuilder subArray = BuilderFactory.startArray();
 676  4
             for (final Object entry : (Object[]) value) {
 677  2
                 subArray.add(entry);
 678  
             }
 679  2
             return new ArrayElement(name, subArray.build());
 680  
         }
 681  
 
 682  2
         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  2
         if (id != null) {
 704  1
             return new ObjectIdElement(name, id);
 705  
         }
 706  1
         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  2
         if (pattern != null) {
 727  1
             return new RegularExpressionElement(name, pattern);
 728  
         }
 729  1
         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  54
         if (value != null) {
 750  53
             return new StringElement(name, value);
 751  
         }
 752  1
         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  2
         if (uuid != null) {
 773  1
             return new UuidElement(name, UuidElement.UUID_SUBTTYPE, uuid);
 774  
         }
 775  1
         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  5155
         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  114
         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  83
         final DocumentBuilderImpl builder = new DocumentBuilderImpl();
 815  249
         for (final DocumentAssignable seedDocument : seedDocuments) {
 816  166
             for (final Element element : seedDocument.asDocument()) {
 817  369
                 builder.remove(element.getName());
 818  369
                 builder.add(element);
 819  369
             }
 820  
         }
 821  83
         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  225
         return new ArrayBuilderImpl();
 831  
     }
 832  
 
 833  
     /**
 834  
      * Creates a new builder factory.
 835  
      */
 836  0
     private BuilderFactory() {
 837  
         // Nothing to do.
 838  0
     }
 839  
 }