1 /*
2 * #%L
3 * TimestampElement.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 java.util.Date;
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 timestamp as the milliseconds since the epoch.
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 TimestampElement extends AbstractElement {
39
40 /** The BSON type for a long. */
41 public static final ElementType TYPE = ElementType.UTC_TIMESTAMP;
42
43 /** Serialization version for the class. */
44 private static final long serialVersionUID = 949598909338399091L;
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 * @return The size of the element when encoded in bytes.
53 */
54 private static long computeSize(final String name) {
55 long result = 10; // type (1) + name null byte (1) + value (8).
56 result += StringEncoder.utf8Size(name);
57
58 return result;
59 }
60
61 /** The BSON timestamp value as the milliseconds since the epoch. */
62 private final long myTimestamp;
63
64 /**
65 * Constructs a new {@link TimestampElement}.
66 *
67 * @param name
68 * The name for the BSON long.
69 * @param value
70 * The BSON timestamp value as the milliseconds since the epoch.
71 * @throws IllegalArgumentException
72 * If the {@code name} is <code>null</code>.
73 */
74 public TimestampElement(final String name, final long value) {
75 this(name, value, computeSize(name));
76 }
77
78 /**
79 * Constructs a new {@link TimestampElement}.
80 *
81 * @param name
82 * The name for the BSON long.
83 * @param value
84 * The BSON timestamp value as the milliseconds since the epoch.
85 * @param size
86 * The size of the element when encoded in bytes. If not known
87 * then use the
88 * {@link TimestampElement#TimestampElement(String, long)}
89 * constructor instead.
90 * @throws IllegalArgumentException
91 * If the {@code name} is <code>null</code>.
92 */
93 public TimestampElement(final String name, final long value, final long size) {
94 super(name, size);
95
96 myTimestamp = value;
97 }
98
99 /**
100 * Accepts the visitor and calls the {@link Visitor#visitTimestamp} method.
101 *
102 * @see Element#accept(Visitor)
103 */
104 @Override
105 public void accept(final Visitor visitor) {
106 visitor.visitTimestamp(getName(), getTime());
107 }
108
109 /**
110 * {@inheritDoc}
111 * <p>
112 * Overridden to compare the times if the base class comparison is equals.
113 * </p>
114 * <p>
115 * Note that for MongoDB {@link MongoTimestampElement} and
116 * {@link TimestampElement} will return equal based on the type. Care is
117 * taken here to make sure that the values return the same value regardless
118 * of comparison order.
119 * </p>
120 */
121 @Override
122 public int compareTo(final Element otherElement) {
123 int result = super.compareTo(otherElement);
124
125 if (result == 0) {
126 // Might be a MongoTimestampElement or TimestampElement.
127 final ElementType otherType = otherElement.getType();
128
129 if (otherType == ElementType.UTC_TIMESTAMP) {
130 result = compare(getTime(),
131 ((TimestampElement) otherElement).getTime());
132 }
133 else {
134 result = compare(getTime(),
135 ((MongoTimestampElement) otherElement).getTime());
136 }
137 }
138
139 return result;
140 }
141
142 /**
143 * Determines if the passed object is of this same type as this object and
144 * if so that its fields are equal.
145 *
146 * @param object
147 * The object to compare to.
148 *
149 * @see java.lang.Object#equals(java.lang.Object)
150 */
151 @Override
152 public boolean equals(final Object object) {
153 boolean result = false;
154 if (this == object) {
155 result = true;
156 }
157 else if ((object != null) && (getClass() == object.getClass())) {
158 final TimestampElement other = (TimestampElement) object;
159
160 result = super.equals(object) && (myTimestamp == other.myTimestamp);
161 }
162 return result;
163 }
164
165 /**
166 * Returns the BSON timestamp value as the milliseconds since the epoch.
167 *
168 * @return The BSON timestamp value as the milliseconds since the epoch.
169 */
170 public long getTime() {
171 return myTimestamp;
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 {@link Date}.
186 * </p>
187 */
188 @Override
189 public Date getValueAsObject() {
190 return new Date(getTime());
191 }
192
193 /**
194 * Computes a reasonable hash code.
195 *
196 * @return The hash code value.
197 */
198 @Override
199 public int hashCode() {
200 int result = 1;
201 result = (31 * result) + super.hashCode();
202 result = (31 * result) + (int) (myTimestamp & 0xFFFFFFFF);
203 result = (31 * result) + (int) ((myTimestamp >> 32) & 0xFFFFFFFF);
204 return result;
205 }
206
207 /**
208 * {@inheritDoc}
209 * <p>
210 * Returns a new {@link TimestampElement}.
211 * </p>
212 */
213 @Override
214 public TimestampElement withName(final String name) {
215 if (getName().equals(name)) {
216 return this;
217 }
218 return new TimestampElement(name, myTimestamp);
219 }
220 }