View Javadoc
1   /*
2    * #%L
3    * SymbolElement.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 com.allanbank.mongodb.bson.Element;
25  import com.allanbank.mongodb.bson.ElementType;
26  import com.allanbank.mongodb.bson.Visitor;
27  import com.allanbank.mongodb.bson.io.StringEncoder;
28  
29  /**
30   * A wrapper for a BSON symbol.
31   * 
32   * @api.yes This class is part of the driver's API. Public and protected members
33   *          will be deprecated for at least 1 non-bugfix release (version
34   *          numbers are <major>.<minor>.<bugfix>) before being
35   *          removed or modified.
36   * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
37   */
38  public class SymbolElement extends AbstractElement {
39  
40      /** The BSON type for a symbol. */
41      public static final ElementType TYPE = ElementType.SYMBOL;
42  
43      /** Serialization version for the class. */
44      private static final long serialVersionUID = -3181997000292958333L;
45  
46      /**
47       * Computes and returns the number of bytes that are used to encode the
48       * element.
49       * 
50       * @param name
51       *            The name for the element.
52       * @param symbol
53       *            The BSON symbol value.
54       * @return The size of the element when encoded in bytes.
55       */
56      private static long computeSize(final String name, final String symbol) {
57          long result = 7; // type (1) + name null byte (1) +
58          // symbol length (4) + symbol null byte (1)
59          result += StringEncoder.utf8Size(name);
60          result += StringEncoder.utf8Size(symbol);
61  
62          return result;
63      }
64  
65      /** The BSON string value. */
66      private final String mySymbol;
67  
68      /**
69       * Constructs a new {@link SymbolElement}.
70       * 
71       * @param name
72       *            The name for the BSON string.
73       * @param symbol
74       *            The BSON symbol value.
75       * @throws IllegalArgumentException
76       *             If the {@code name} or {@code symbol} is <code>null</code>.
77       */
78      public SymbolElement(final String name, final String symbol) {
79          this(name, symbol, computeSize(name, symbol));
80      }
81  
82      /**
83       * Constructs a new {@link SymbolElement}.
84       * 
85       * @param name
86       *            The name for the BSON string.
87       * @param symbol
88       *            The BSON symbol value.
89       * @param size
90       *            The size of the element when encoded in bytes. If not known
91       *            then use the
92       *            {@link StringElement#StringElement(String, String)}
93       *            constructor instead.
94       * @throws IllegalArgumentException
95       *             If the {@code name} or {@code symbol} is <code>null</code>.
96       */
97      public SymbolElement(final String name, final String symbol, final long size) {
98          super(name, size);
99  
100         assertNotNull(symbol, "Symbol element's symbol cannot be null.");
101 
102         mySymbol = symbol;
103     }
104 
105     /**
106      * Accepts the visitor and calls the {@link Visitor#visitSymbol} method.
107      * 
108      * @see Element#accept(Visitor)
109      */
110     @Override
111     public void accept(final Visitor visitor) {
112         visitor.visitSymbol(getName(), getSymbol());
113     }
114 
115     /**
116      * {@inheritDoc}
117      * <p>
118      * Overridden to compare the string values if the base class comparison is
119      * equals.
120      * </p>
121      * <p>
122      * Note that for MongoDB {@link SymbolElement} and {@link StringElement}
123      * will return equal based on the type. Care is taken here to make sure that
124      * the values return the same value regardless of comparison order.
125      * </p>
126      * <p>
127      * Note: Comparison of strings in MongoDB does not use a collator. This
128      * class emulates the MongoDB behavior and orders the string elements based
129      * on the UTF-8 encoding of the strings.
130      * </p>
131      */
132     @Override
133     public int compareTo(final Element otherElement) {
134         int result = super.compareTo(otherElement);
135 
136         if (result == 0) {
137             // Might be a StringElement or SymbolElement.
138             final ElementType otherType = otherElement.getType();
139 
140             if (otherType == ElementType.SYMBOL) {
141                 result = StringElement.utf8Compare(mySymbol,
142                         ((SymbolElement) otherElement).getSymbol());
143             }
144             else {
145                 result = StringElement.utf8Compare(mySymbol,
146                         ((StringElement) otherElement).getValue());
147             }
148         }
149 
150         return result;
151     }
152 
153     /**
154      * Determines if the passed object is of this same type as this object and
155      * if so that its fields are equal.
156      * 
157      * @param object
158      *            The object to compare to.
159      * 
160      * @see java.lang.Object#equals(java.lang.Object)
161      */
162     @Override
163     public boolean equals(final Object object) {
164         boolean result = false;
165         if (this == object) {
166             result = true;
167         }
168         else if ((object != null) && (getClass() == object.getClass())) {
169             final SymbolElement other = (SymbolElement) object;
170 
171             result = super.equals(object)
172                     && nullSafeEquals(mySymbol, other.mySymbol);
173         }
174         return result;
175     }
176 
177     /**
178      * Returns the BSON symbol value.
179      * 
180      * @return The BSON symbol value.
181      */
182     public String getSymbol() {
183         return mySymbol;
184     }
185 
186     /**
187      * {@inheritDoc}
188      */
189     @Override
190     public ElementType getType() {
191         return TYPE;
192     }
193 
194     /**
195      * {@inheritDoc}
196      * <p>
197      * Returns the {@link String} symbol.
198      * </p>
199      */
200     @Override
201     public String getValueAsObject() {
202         return getSymbol();
203     }
204 
205     /**
206      * {@inheritDoc}
207      * <p>
208      * Returns the {@link String} symbol.
209      * </p>
210      */
211     @Override
212     public String getValueAsString() {
213         return getSymbol();
214     }
215 
216     /**
217      * Computes a reasonable hash code.
218      * 
219      * @return The hash code value.
220      */
221     @Override
222     public int hashCode() {
223         int result = 1;
224         result = (31 * result) + super.hashCode();
225         result = (31 * result) + ((mySymbol != null) ? mySymbol.hashCode() : 3);
226         return result;
227     }
228 
229     /**
230      * {@inheritDoc}
231      * <p>
232      * Returns a new {@link SymbolElement}.
233      * </p>
234      */
235     @Override
236     public SymbolElement withName(final String name) {
237         if (getName().equals(name)) {
238             return this;
239         }
240         return new SymbolElement(name, mySymbol);
241     }
242 }