View Javadoc
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 }