Coverage Report - com.allanbank.mongodb.bson.element.UuidElement
 
Classes in this File Line Coverage Branch Coverage Complexity
UuidElement
100%
68/68
95%
21/22
2.083
 
 1  
 /*
 2  
  * #%L
 3  
  * UuidElement.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.element;
 21  
 
 22  
 import static com.allanbank.mongodb.util.Assertions.assertNotNull;
 23  
 
 24  
 import java.util.UUID;
 25  
 
 26  
 import com.allanbank.mongodb.bson.io.EndianUtils;
 27  
 import com.allanbank.mongodb.util.IOUtils;
 28  
 
 29  
 /**
 30  
  * UuidElement provides a helper element for handling UUID {@link BinaryElement}
 31  
  * sub-types.
 32  
  * <p>
 33  
  * If no sub-type is provided this class defaults to the standardized sub-type 4
 34  
  * binary element which encodes the UUID from most significant byte to least
 35  
  * significant byte. If the deprecated sub-type 3 is specified this class
 36  
  * assumes the legacy Java encoding of the UUID which encodes the most
 37  
  * significant long in least-significant-byte order and then the least
 38  
  * significant long in least-significant-byte order.
 39  
  * </p>
 40  
  * 
 41  
  * @api.yes This class is part of the driver's API. Public and protected members
 42  
  *          will be deprecated for at least 1 non-bugfix release (version
 43  
  *          numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) before being
 44  
  *          removed or modified.
 45  
  * @copyright 2012-2013, Allanbank Consulting, Inc., All Rights Reserved
 46  
  */
 47  16
 public class UuidElement extends BinaryElement {
 48  
 
 49  
     /**
 50  
      * The legacy (reverse byte order for high and low long values) subtype for
 51  
      * the UUID.
 52  
      */
 53  
     public static final byte LEGACY_UUID_SUBTTYPE = 3;
 54  
 
 55  
     /** The length for the UUID binary value. */
 56  
     public static final int UUID_BINARY_LENGTH = 16;
 57  
 
 58  
     /** The default subtype for the UUID. */
 59  
     public static final byte UUID_SUBTTYPE = 4;
 60  
 
 61  
     /** The serialization version for the class. */
 62  
     private static final long serialVersionUID = 6461067538910973839L;
 63  
 
 64  
     /**
 65  
      * Converts the UUID value to a byte array based on the subtype.
 66  
      * 
 67  
      * @param uuidSubttype
 68  
      *            The subtype for the UUID encoding.
 69  
      * @param value
 70  
      *            The UUID value to convert.
 71  
      * @return The byte encoding.
 72  
      */
 73  
     private static byte[] toBytes(final byte uuidSubttype, final UUID value) {
 74  100
         assertNotNull(value,
 75  
                 "The UUID value for a UuidElement must not be null.");
 76  
 
 77  96
         long high = value.getMostSignificantBits();
 78  96
         long low = value.getLeastSignificantBits();
 79  
 
 80  96
         if (uuidSubttype == LEGACY_UUID_SUBTTYPE) {
 81  34
             high = EndianUtils.swap(high);
 82  34
             low = EndianUtils.swap(low);
 83  
         }
 84  
 
 85  96
         final byte[] result = new byte[16];
 86  
 
 87  96
         result[0] = (byte) ((high >> 56) & 0xFF);
 88  96
         result[1] = (byte) ((high >> 48) & 0xFF);
 89  96
         result[2] = (byte) ((high >> 40) & 0xFF);
 90  96
         result[3] = (byte) ((high >> 32) & 0xFF);
 91  96
         result[4] = (byte) ((high >> 24) & 0xFF);
 92  96
         result[5] = (byte) ((high >> 16) & 0xFF);
 93  96
         result[6] = (byte) ((high >> 8) & 0xFF);
 94  96
         result[7] = (byte) (high & 0xFF);
 95  96
         result[8] = (byte) ((low >> 56) & 0xFF);
 96  96
         result[9] = (byte) ((low >> 48) & 0xFF);
 97  96
         result[10] = (byte) ((low >> 40) & 0xFF);
 98  96
         result[11] = (byte) ((low >> 32) & 0xFF);
 99  96
         result[12] = (byte) ((low >> 24) & 0xFF);
 100  96
         result[13] = (byte) ((low >> 16) & 0xFF);
 101  96
         result[14] = (byte) ((low >> 8) & 0xFF);
 102  96
         result[15] = (byte) (low & 0xFF);
 103  
 
 104  96
         return result;
 105  
     }
 106  
 
 107  
     /** The UUID value created. */
 108  
     private final UUID myUuid;
 109  
 
 110  
     /**
 111  
      * Creates a new UuidElement.
 112  
      * 
 113  
      * @param name
 114  
      *            The name for the element.
 115  
      * @param subType
 116  
      *            The subtype for the UUID element.
 117  
      * @param value
 118  
      *            The UUID bytes for the element.
 119  
      * @throws IllegalArgumentException
 120  
      *             If the {@code name} or {@code value} is <code>null</code>. If
 121  
      *             the subType is not {@link #UUID_SUBTTYPE} or
 122  
      *             {@link #LEGACY_UUID_SUBTTYPE}. If the value is not a 16 bytes
 123  
      *             long.
 124  
      */
 125  
     public UuidElement(final String name, final byte subType, final byte[] value) {
 126  2
         super(name, subType, value);
 127  
 
 128  2
         myUuid = toUuid(subType, value);
 129  2
     }
 130  
 
 131  
     /**
 132  
      * Creates a new UuidElement.
 133  
      * 
 134  
      * @param name
 135  
      *            The name for the element.
 136  
      * @param subType
 137  
      *            The subtype for the UUID element.
 138  
      * @param value
 139  
      *            The UUID bytes for the element.
 140  
      * @param size
 141  
      *            The size of the element when encoded in bytes. If not known
 142  
      *            then use the
 143  
      *            {@link UuidElement#UuidElement(String, byte, byte[])}
 144  
      *            constructor instead.
 145  
      * @throws IllegalArgumentException
 146  
      *             If the {@code name} or {@code value} is <code>null</code>. If
 147  
      *             the subType is not {@link #UUID_SUBTTYPE} or
 148  
      *             {@link #LEGACY_UUID_SUBTTYPE}. If the value is not a 16 bytes
 149  
      *             long.
 150  
      */
 151  
     public UuidElement(final String name, final byte subType,
 152  
             final byte[] value, final long size) {
 153  3
         super(name, subType, value, size);
 154  
 
 155  3
         myUuid = toUuid(subType, value);
 156  2
     }
 157  
 
 158  
     /**
 159  
      * Creates a new UuidElement.
 160  
      * 
 161  
      * @param name
 162  
      *            The name for the element.
 163  
      * @param subType
 164  
      *            The subtype for the UUID element.
 165  
      * @param value
 166  
      *            The UUID value for the element.
 167  
      * @throws IllegalArgumentException
 168  
      *             If the {@code name} or {@code value} is <code>null</code>.
 169  
      */
 170  
     public UuidElement(final String name, final byte subType, final UUID value) {
 171  81
         super(name, subType, toBytes(subType, value));
 172  
 
 173  74
         myUuid = value;
 174  74
     }
 175  
 
 176  
     /**
 177  
      * Creates a new UuidElement.
 178  
      * 
 179  
      * @param name
 180  
      *            The name for the element.
 181  
      * @param value
 182  
      *            The UUID value for the element.
 183  
      * @throws IllegalArgumentException
 184  
      *             If the {@code name} or {@code value} is <code>null</code>.
 185  
      */
 186  
     public UuidElement(final String name, final UUID value) {
 187  19
         super(name, UUID_SUBTTYPE, toBytes(UUID_SUBTTYPE, value));
 188  
 
 189  19
         myUuid = value;
 190  19
     }
 191  
 
 192  
     /**
 193  
      * Determines if the passed object is of this same type as this object and
 194  
      * if so that its fields are equal.
 195  
      * 
 196  
      * @param object
 197  
      *            The object to compare to.
 198  
      * 
 199  
      * @see java.lang.Object#equals(java.lang.Object)
 200  
      */
 201  
     @Override
 202  
     public boolean equals(final Object object) {
 203  313
         boolean result = false;
 204  313
         if (this == object) {
 205  20
             result = true;
 206  
         }
 207  293
         else if ((object != null) && (getClass() == object.getClass())) {
 208  233
             final UuidElement other = (UuidElement) object;
 209  
 
 210  233
             result = super.equals(object) && myUuid.equals(other.myUuid);
 211  
         }
 212  313
         return result;
 213  
     }
 214  
 
 215  
     /**
 216  
      * Returns the {@link UUID} value.
 217  
      * 
 218  
      * @return The {@link UUID} value.
 219  
      */
 220  
     public UUID getUuid() {
 221  7
         return myUuid;
 222  
     }
 223  
 
 224  
     /**
 225  
      * {@inheritDoc}
 226  
      * <p>
 227  
      * Returns the UUID value.
 228  
      * </p>
 229  
      * <p>
 230  
      * <b>Note:</b> This value will not be recreated is a Object-->Element
 231  
      * conversion. The sub type is lost in this conversion to an {@link Object}.
 232  
      * </p>
 233  
      */
 234  
     @Override
 235  
     public UUID getValueAsObject() {
 236  1
         return myUuid;
 237  
     }
 238  
 
 239  
     /**
 240  
      * {@inheritDoc}
 241  
      * <p>
 242  
      * Returns the result of the {@link UUID#toString()}.
 243  
      * </p>
 244  
      */
 245  
     @Override
 246  
     public String getValueAsString() {
 247  1
         return myUuid.toString();
 248  
     }
 249  
 
 250  
     /**
 251  
      * Computes a reasonable hash code.
 252  
      * 
 253  
      * @return The hash code value.
 254  
      */
 255  
     @Override
 256  
     public int hashCode() {
 257  420
         int result = 1;
 258  420
         result = (31 * result) + super.hashCode();
 259  420
         result = (31 * result) + myUuid.hashCode();
 260  420
         return result;
 261  
     }
 262  
 
 263  
     /**
 264  
      * {@inheritDoc}
 265  
      * <p>
 266  
      * Returns a new {@link BinaryElement}.
 267  
      * </p>
 268  
      */
 269  
     @Override
 270  
     public UuidElement withName(final String name) {
 271  18
         if (getName().equals(name)) {
 272  16
             return this;
 273  
         }
 274  2
         return new UuidElement(name, getSubType(), myUuid);
 275  
     }
 276  
 
 277  
     /**
 278  
      * Converts the UUID binary form into a UUID object.
 279  
      * 
 280  
      * @param subType
 281  
      *            The sub-type for the UUID encoding.
 282  
      * @param value
 283  
      *            The encoded UUID.
 284  
      * @return The UUID encoded in the {@code value}.
 285  
      * @throws IllegalArgumentException
 286  
      *             If the length of the {@code value} array is not
 287  
      *             {@value #UUID_BINARY_LENGTH}.
 288  
      */
 289  
     private UUID toUuid(final byte subType, final byte[] value)
 290  
             throws IllegalArgumentException {
 291  
 
 292  5
         if (value.length == UUID_BINARY_LENGTH) {
 293  4
             long high = 0;
 294  4
             long low = 0;
 295  
 
 296  36
             for (int i = 0; i < 8; ++i) {
 297  32
                 high <<= Byte.SIZE;
 298  32
                 high += (value[i] & 0xFF);
 299  
             }
 300  36
             for (int i = 8; i < 16; ++i) {
 301  32
                 low <<= Byte.SIZE;
 302  32
                 low += (value[i] & 0xFF);
 303  
             }
 304  
 
 305  4
             if (subType == LEGACY_UUID_SUBTTYPE) {
 306  2
                 high = EndianUtils.swap(high);
 307  2
                 low = EndianUtils.swap(low);
 308  
             }
 309  4
             return new UUID(high, low);
 310  
         }
 311  
 
 312  1
         throw new IllegalArgumentException(
 313  
                 "The value for a UUID must be 16 bytes long: "
 314  
                         + IOUtils.toHex(value));
 315  
     }
 316  
 }