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 }