Coverage Report - com.allanbank.mongodb.bson.impl.AbstractDocument
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractDocument
100%
67/67
100%
34/34
2.25
 
 1  
 /*
 2  
  * #%L
 3  
  * AbstractDocument.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  
 
 21  
 package com.allanbank.mongodb.bson.impl;
 22  
 
 23  
 import java.io.StringWriter;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Arrays;
 26  
 import java.util.Collections;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.regex.Pattern;
 31  
 import java.util.regex.PatternSyntaxException;
 32  
 
 33  
 import com.allanbank.mongodb.bson.Document;
 34  
 import com.allanbank.mongodb.bson.Element;
 35  
 import com.allanbank.mongodb.bson.Visitor;
 36  
 import com.allanbank.mongodb.bson.element.JsonSerializationVisitor;
 37  
 import com.allanbank.mongodb.util.PatternUtils;
 38  
 
 39  
 /**
 40  
  * AbstractDocument provides a base class for all document implementations with
 41  
  * the common functionality.
 42  
  * 
 43  
  * @copyright 2013, Allanbank Consulting, Inc., All Rights Reserved
 44  
  */
 45  
 public abstract class AbstractDocument implements Document {
 46  
 
 47  
     /** The empty list of elements. */
 48  1
     public static final List<Element> EMPTY_ELEMENTS = Collections.emptyList();
 49  
 
 50  
     /** The base type (interface) for all elements. */
 51  1
     protected static final Class<Element> ELEMENT_TYPE = Element.class;
 52  
 
 53  
     /** The serialization id for the class. */
 54  
     private static final long serialVersionUID = -425294885378885212L;
 55  
 
 56  
     /**
 57  
      * Creates a new AbstractDocument.
 58  
      */
 59  
     public AbstractDocument() {
 60  313675
         super();
 61  313675
     }
 62  
 
 63  
     /**
 64  
      * Accepts the visitor and calls the {@link Visitor#visitDocument} method.
 65  
      * 
 66  
      * @see Element#accept(Visitor)
 67  
      */
 68  
     @Override
 69  
     public void accept(final Visitor visitor) {
 70  9817
         visitor.visit(getElements());
 71  9817
     }
 72  
 
 73  
     /**
 74  
      * {@inheritDoc}
 75  
      * <p>
 76  
      * Returns this document.
 77  
      * </p>
 78  
      */
 79  
     @Override
 80  
     public Document asDocument() {
 81  2618562
         return this;
 82  
     }
 83  
 
 84  
     /**
 85  
      * Returns true if the document contains an element with the specified name.
 86  
      * 
 87  
      * @see Document#contains(String)
 88  
      */
 89  
     @Override
 90  
     public boolean contains(final String name) {
 91  200281
         return getElementMap().containsKey(name);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Determines if the passed object is of this same type as this object and
 96  
      * if so that its fields are equal.
 97  
      * 
 98  
      * @param object
 99  
      *            The object to compare to.
 100  
      * 
 101  
      * @see java.lang.Object#equals(java.lang.Object)
 102  
      */
 103  
     @Override
 104  
     public boolean equals(final Object object) {
 105  21412
         boolean result = false;
 106  21412
         if (this == object) {
 107  7094
             result = true;
 108  
         }
 109  14318
         else if ((object != null) && (object instanceof Document)) {
 110  14255
             final Document other = (Document) object;
 111  
 
 112  14255
             result = getElements().equals(other.getElements());
 113  
         }
 114  21412
         return result;
 115  
     }
 116  
 
 117  
     /**
 118  
      * {@inheritDoc}
 119  
      * <p>
 120  
      * Searches this sub-elements for matching elements on the path and are of
 121  
      * the right type.
 122  
      * </p>
 123  
      * 
 124  
      * @see Document#find
 125  
      */
 126  
     @Override
 127  
     public <E extends Element> List<E> find(final Class<E> clazz,
 128  
             final String... nameRegexs) {
 129  539
         List<E> elements = Collections.emptyList();
 130  538
         if (0 < nameRegexs.length) {
 131  536
             final List<Element> docElements = getElements();
 132  537
             final String nameRegex = nameRegexs[0];
 133  536
             final String[] subNameRegexs = Arrays.copyOfRange(nameRegexs, 1,
 134  
                     nameRegexs.length);
 135  
 
 136  536
             elements = new ArrayList<E>();
 137  
             try {
 138  536
                 final Pattern pattern = PatternUtils.toPattern(nameRegex);
 139  532
                 for (final Element element : docElements) {
 140  1047
                     if (pattern.matcher(element.getName()).matches()) {
 141  192
                         elements.addAll(element.find(clazz, subNameRegexs));
 142  
                     }
 143  1047
                 }
 144  
             }
 145  4
             catch (final PatternSyntaxException pse) {
 146  
                 // Assume a non-pattern?
 147  4
                 for (final Element element : docElements) {
 148  4
                     if (nameRegex.equals(element.getName())) {
 149  2
                         elements.addAll(element.find(clazz, subNameRegexs));
 150  
                     }
 151  4
                 }
 152  532
             }
 153  
         }
 154  
 
 155  
         // End of the path but we are a document?
 156  538
         return elements;
 157  
     }
 158  
 
 159  
     /**
 160  
      * {@inheritDoc}
 161  
      * <p>
 162  
      * Searches this sub-elements for matching elements on the path.
 163  
      * </p>
 164  
      * 
 165  
      * @see Document#find
 166  
      */
 167  
     @Override
 168  
     public List<Element> find(final String... nameRegexs) {
 169  24
         return find(ELEMENT_TYPE, nameRegexs);
 170  
     }
 171  
 
 172  
     /**
 173  
      * {@inheritDoc}
 174  
      * <p>
 175  
      * Searches this sub-elements for matching elements on the path and are of
 176  
      * the right type.
 177  
      * </p>
 178  
      * 
 179  
      * @see Document#findFirst
 180  
      */
 181  
     @Override
 182  
     public <E extends Element> E findFirst(final Class<E> clazz,
 183  
             final String... nameRegexs) {
 184  2952
         E element = null;
 185  2954
         if (0 < nameRegexs.length) {
 186  2951
             final List<Element> docElements = getElements();
 187  2951
             final String nameRegex = nameRegexs[0];
 188  2952
             final String[] subNameRegexs = Arrays.copyOfRange(nameRegexs, 1,
 189  
                     nameRegexs.length);
 190  
 
 191  
             try {
 192  2951
                 final Pattern pattern = PatternUtils.toPattern(nameRegex);
 193  2944
                 final Iterator<Element> iter = docElements.iterator();
 194  8562
                 while (iter.hasNext() && (element == null)) {
 195  5618
                     final Element docElement = iter.next();
 196  5619
                     if (pattern.matcher(docElement.getName()).matches()) {
 197  525
                         element = docElement.findFirst(clazz, subNameRegexs);
 198  
                     }
 199  5620
                 }
 200  
             }
 201  8
             catch (final PatternSyntaxException pse) {
 202  
                 // Assume a non-pattern?
 203  8
                 final Iterator<Element> iter = docElements.iterator();
 204  16
                 while (iter.hasNext() && (element == null)) {
 205  8
                     final Element docElement = iter.next();
 206  8
                     if (nameRegex.equals(docElement.getName())) {
 207  6
                         element = docElement.findFirst(clazz, subNameRegexs);
 208  
                     }
 209  8
                 }
 210  2946
             }
 211  
         }
 212  
 
 213  
         // End of the path but we are a document?
 214  2956
         return element;
 215  
     }
 216  
 
 217  
     /**
 218  
      * {@inheritDoc}
 219  
      * <p>
 220  
      * Searches this sub-elements for matching elements on the path and are of
 221  
      * the right type.
 222  
      * </p>
 223  
      * 
 224  
      * @see Document#findFirst
 225  
      */
 226  
     @Override
 227  
     public Element findFirst(final String... nameRegexs) {
 228  446
         return findFirst(ELEMENT_TYPE, nameRegexs);
 229  
     }
 230  
 
 231  
     /**
 232  
      * Returns the element with the specified name and type or null if no
 233  
      * element with that name and type exists.
 234  
      * 
 235  
      * @see Document#get(String)
 236  
      */
 237  
     @Override
 238  
     public <E extends Element> E get(final Class<E> clazz, final String name) {
 239  892
         final Element element = get(name);
 240  892
         if ((element != null) && clazz.isAssignableFrom(element.getClass())) {
 241  278
             return clazz.cast(element);
 242  
         }
 243  614
         return null;
 244  
     }
 245  
 
 246  
     /**
 247  
      * Returns the element with the specified name or null if no element with
 248  
      * that name exists.
 249  
      * 
 250  
      * @see Document#get(String)
 251  
      */
 252  
     @Override
 253  
     public Element get(final String name) {
 254  3661
         return getElementMap().get(name);
 255  
     }
 256  
 
 257  
     /**
 258  
      * {@inheritDoc}
 259  
      */
 260  
     @Override
 261  
     public abstract List<Element> getElements();
 262  
 
 263  
     /**
 264  
      * Computes a reasonable hash code.
 265  
      * 
 266  
      * @return The hash code value.
 267  
      */
 268  
     @Override
 269  
     public int hashCode() {
 270  3718017
         return getElements().hashCode();
 271  
     }
 272  
 
 273  
     /**
 274  
      * Returns an iterator over the documents elements.
 275  
      * 
 276  
      * @see Iterable#iterator()
 277  
      */
 278  
     @Override
 279  
     public Iterator<Element> iterator() {
 280  2889
         return getElements().iterator();
 281  
     }
 282  
 
 283  
     /**
 284  
      * String form of the object.
 285  
      * 
 286  
      * @return A human readable form of the object.
 287  
      * 
 288  
      * @see java.lang.Object#toString()
 289  
      */
 290  
     @Override
 291  
     public String toString() {
 292  2347
         final StringWriter writer = new StringWriter();
 293  2347
         final JsonSerializationVisitor visitor = new JsonSerializationVisitor(
 294  
                 writer, false);
 295  
 
 296  2347
         accept(visitor);
 297  
 
 298  2347
         return writer.toString();
 299  
     }
 300  
 
 301  
     /**
 302  
      * Returns the mapping from the names of elements to the element.
 303  
      * 
 304  
      * @return The mapping from the names of elements to the element.
 305  
      */
 306  
     protected abstract Map<String, Element> getElementMap();
 307  
 
 308  
 }