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