Coverage Report - com.allanbank.mongodb.bson.impl.ImmutableDocument
 
Classes in this File Line Coverage Branch Coverage Complexity
ImmutableDocument
79%
23/29
100%
6/6
1.429
 
 1  
 /*
 2  
  * #%L
 3  
  * ImmutableDocument.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.impl;
 21  
 
 22  
 import java.io.IOException;
 23  
 import java.io.ObjectInputStream;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Collections;
 26  
 import java.util.HashMap;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 
 30  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 31  
 import com.allanbank.mongodb.bson.Element;
 32  
 
 33  
 /**
 34  
  * A root level document that is truly immutable.
 35  
  * <p>
 36  
  * Documents normally returned from the document builders have the ability to be
 37  
  * modified by injecting an {@code _id} field into the document. This document
 38  
  * class does not have that ability.
 39  
  * </p>
 40  
  * <p>
 41  
  * Most users will not need to use this class except when creating static
 42  
  * documents within classes. The intended usage is then to use the builder when
 43  
  * constructing the immutable document: <blockquote>
 44  
  * 
 45  
  * <pre>
 46  
  * <code>
 47  
  * public static final Document QUERY;
 48  
  * 
 49  
  * ...
 50  
  * static {
 51  
  *    DocumentBuilder builder = BuilderFactory.start();
 52  
  * 
 53  
  *    builder.add(...);
 54  
  *    ...
 55  
  * 
 56  
  *    QUERY = new ImmutableDocument(builder);
 57  
  * }
 58  
  * </code>
 59  
  * </pre>
 60  
  * 
 61  
  * </blockquote>
 62  
  * 
 63  
  * @api.yes This interface is part of the driver's API. Public and protected
 64  
  *          members will be deprecated for at least 1 non-bugfix release
 65  
  *          (version numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;)
 66  
  *          before being removed or modified.
 67  
  * @copyright 2011-2014, Allanbank Consulting, Inc., All Rights Reserved
 68  
  */
 69  
 public class ImmutableDocument extends AbstractDocument {
 70  
 
 71  
     /** Serialization version for the class. */
 72  
     private static final long serialVersionUID = -2875918328146027037L;
 73  
 
 74  
     /**
 75  
      * Constructed when a user tries to access the elements of the document by
 76  
      * name.
 77  
      */
 78  
     private volatile Map<String, Element> myElementMap;
 79  
 
 80  
     /** The elements of the document. */
 81  
     private final List<Element> myElements;
 82  
 
 83  
     /** The size of the document when encoded as bytes. */
 84  
     private transient long mySize;
 85  
 
 86  
     /**
 87  
      * Constructs a new {@link ImmutableDocument}.
 88  
      * 
 89  
      * @param document
 90  
      *            The elements for the BSON document.
 91  
      */
 92  93
     public ImmutableDocument(final DocumentAssignable document) {
 93  
 
 94  93
         final List<Element> elements = document.asDocument().getElements();
 95  
 
 96  93
         myElements = Collections.unmodifiableList(new ArrayList<Element>(
 97  
                 elements));
 98  93
         myElementMap = null;
 99  93
         mySize = computeSize();
 100  93
     }
 101  
 
 102  
     /**
 103  
      * Constructs a new {@link ImmutableDocument}.
 104  
      * 
 105  
      * @param document
 106  
      *            The elements for the BSON document.
 107  
      * @param size
 108  
      *            The size of the document when encoded in bytes. If not known
 109  
      *            then use the
 110  
      *            {@link ImmutableDocument#ImmutableDocument(DocumentAssignable)}
 111  
      *            constructor instead.
 112  
      */
 113  0
     public ImmutableDocument(final DocumentAssignable document, final long size) {
 114  
 
 115  0
         final List<Element> elements = document.asDocument().getElements();
 116  
 
 117  0
         myElements = Collections.unmodifiableList(new ArrayList<Element>(
 118  
                 elements));
 119  0
         myElementMap = null;
 120  0
         mySize = size;
 121  0
     }
 122  
 
 123  
     /**
 124  
      * Returns the elements in the document.
 125  
      * 
 126  
      * @return The elements in the document.
 127  
      */
 128  
     @Override
 129  
     public List<Element> getElements() {
 130  2089
         return myElements;
 131  
     }
 132  
 
 133  
     /**
 134  
      * Returns the size of the document when encoded as bytes.
 135  
      * 
 136  
      * @return The size of the document when encoded as bytes.
 137  
      */
 138  
     @Override
 139  
     public long size() {
 140  278
         return mySize;
 141  
     }
 142  
 
 143  
     /**
 144  
      * Returns a map from the element names to the elements in the document.
 145  
      * Used for faster by-name access.
 146  
      * 
 147  
      * @return The element name to element mapping.
 148  
      */
 149  
     @Override
 150  
     protected Map<String, Element> getElementMap() {
 151  184
         if (myElementMap == null) {
 152  11
             final Map<String, Element> mapping = new HashMap<String, Element>(
 153  
                     myElements.size() << 1);
 154  
 
 155  11
             for (final Element element : myElements) {
 156  14
                 mapping.put(element.getName(), element);
 157  14
             }
 158  
 
 159  
             // Swap the finished map into position.
 160  11
             myElementMap = mapping;
 161  
         }
 162  
 
 163  184
         return myElementMap;
 164  
     }
 165  
 
 166  
     /**
 167  
      * Computes and returns the length of the document in bytes.
 168  
      * 
 169  
      * @return The length of the document in bytes.
 170  
      */
 171  
     private long computeSize() {
 172  95
         long result = 5; // int length (4) + terminal null byte (1).
 173  95
         for (final Element element : myElements) {
 174  198
             result += element.size();
 175  198
         }
 176  
 
 177  95
         return result;
 178  
     }
 179  
 
 180  
     /**
 181  
      * Sets the transient state of this document.
 182  
      * 
 183  
      * @param in
 184  
      *            The input stream.
 185  
      * @throws ClassNotFoundException
 186  
      *             On a failure loading a class in this classed reachable tree.
 187  
      * @throws IOException
 188  
      *             On a failure reading from the stream.
 189  
      */
 190  
     private void readObject(final ObjectInputStream in)
 191  
             throws ClassNotFoundException, IOException {
 192  2
         in.defaultReadObject();
 193  2
         mySize = computeSize();
 194  2
     }
 195  
 }