1 /*
2 * #%L
3 * DocumentReference.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
21 package com.allanbank.mongodb.bson;
22
23 import static com.allanbank.mongodb.util.Assertions.assertNotNull;
24
25 import java.io.Serializable;
26
27 import com.allanbank.mongodb.bson.builder.BuilderFactory;
28 import com.allanbank.mongodb.bson.builder.DocumentBuilder;
29
30 /**
31 * DocumentReference provides a standard MongoDB reference to a document within
32 * a collection. This is commonly referred to as a DBRef.
33 * <p>
34 * A DocumentReference contains:
35 * <ol>
36 * <li>The name of the collection where the referenced document resides:
37 * {@code $ref}.</li>
38 * <li>The value of the _id field in the referenced document: {@code $id}.</li>
39 * <li>The name of the database where the referenced document resides:
40 * {@code $db} (Optional).</li>
41 * </ol>
42 *
43 * @see <a
44 * href="http://docs.mongodb.org/manual/applications/database-references/#dbref">MongoDB
45 * DBRef Information</a>
46 * @api.yes This class is part of the driver's API. Public and protected members
47 * will be deprecated for at least 1 non-bugfix release (version
48 * numbers are <major>.<minor>.<bugfix>) before being
49 * removed or modified.
50 * @copyright 2012-2013, Allanbank Consulting, Inc., All Rights Reserved
51 */
52 public class DocumentReference implements DocumentAssignable, Serializable {
53
54 /** The name for the collection name field. */
55 public static final String COLLECTION_FIELD_NAME = "$ref";
56
57 /** The name for the database name field. */
58 public static final String DATABASE_FIELD_NAME = "$db";
59
60 /** The name for the id field. */
61 public static final String ID_FIELD_NAME = "$id";
62
63 /** The serialization version for the class. */
64 private static final long serialVersionUID = 7597767390422754639L;
65
66 /** The name of the collection being referenced. */
67 private final String myCollectionName;
68
69 /** The name of the database being referenced. */
70 private final String myDatabaseName;
71
72 /** The id of the document being referenced. */
73 private final Element myId;
74
75 /**
76 * Creates a new DocumentReference.
77 *
78 * @param collectionName
79 * The name of the collection being referenced.
80 * @param id
81 * The id of the document being referenced. The name of the
82 * element is ignored within the {@link DocumentReference}.
83 * @throws IllegalArgumentException
84 * If the {@code collectionName} or {@code id} are
85 * <code>null</code>.
86 */
87 public DocumentReference(final String collectionName, final Element id)
88 throws IllegalArgumentException {
89 this(null, collectionName, id);
90 }
91
92 /**
93 * Creates a new DocumentReference.
94 *
95 * @param databaseName
96 * The name of the database being referenced.
97 * @param collectionName
98 * The name of the collection being referenced.
99 * @param id
100 * The id of the document being referenced. The name of the
101 * element is ignored within the {@link DocumentReference}.
102 * @throws IllegalArgumentException
103 * If the {@code collectionName} or {@code id} are
104 * <code>null</code>.
105 */
106 public DocumentReference(final String databaseName,
107 final String collectionName, final Element id)
108 throws IllegalArgumentException {
109
110 assertNotNull(collectionName,
111 "The collection name of a Document Reference (DBRef) cannot be null.");
112 assertNotNull(id,
113 "The id of a Document Reference (DBRef) cannot be null.");
114
115 myDatabaseName = databaseName;
116 myCollectionName = collectionName;
117 myId = id.withName(ID_FIELD_NAME);
118 }
119
120 /**
121 * {@inheritDoc}
122 * <p>
123 * Overridden to return a DBRef style document. This is the reference as a
124 * document <em>not</em> the referenced document.
125 * </p>
126 */
127 @Override
128 public Document asDocument() {
129 final DocumentBuilder builder = BuilderFactory.start();
130
131 builder.add(COLLECTION_FIELD_NAME, myCollectionName);
132 builder.add(myId.withName(ID_FIELD_NAME));
133 if (myDatabaseName != null) {
134 builder.add(DATABASE_FIELD_NAME, myDatabaseName);
135 }
136
137 return builder.asDocument();
138 }
139
140 /**
141 * {@inheritDoc}
142 * <p>
143 * Overridden to compare the {@code object} to this
144 * {@link DocumentReference} .
145 * </p>
146 */
147 @Override
148 public boolean equals(final Object object) {
149 boolean result = false;
150 if (this == object) {
151 result = true;
152 }
153 else if ((object != null) && (getClass() == object.getClass())) {
154 final DocumentReference other = (DocumentReference) object;
155
156 result = myCollectionName.equals(other.myCollectionName)
157 && myId.withName(ID_FIELD_NAME).equals(
158 other.myId.withName(ID_FIELD_NAME))
159 && nullSafeEquals(myDatabaseName, other.myDatabaseName);
160 }
161 return result;
162 }
163
164 /**
165 * Returns the name of the collection being referenced.
166 *
167 * @return The name of the collection being referenced.
168 */
169 public String getCollectionName() {
170 return myCollectionName;
171 }
172
173 /**
174 * Returns the name of the database being referenced. This may be
175 * <code>null</code>.
176 *
177 * @return The name of the database being referenced.
178 */
179 public String getDatabaseName() {
180 return myDatabaseName;
181 }
182
183 /**
184 * Returns the id of the document being referenced.
185 *
186 * @return The id of the document being referenced.
187 */
188 public Element getId() {
189 return myId;
190 }
191
192 /**
193 * {@inheritDoc}
194 * <p>
195 * Overridden to compute a reasonable hash for this
196 * {@link DocumentReference}.
197 * </p>
198 */
199 @Override
200 public int hashCode() {
201 int result = 1;
202 result = (31 * result) + myCollectionName.hashCode();
203 result = (31 * result) + myId.withName(ID_FIELD_NAME).hashCode();
204 result = (31 * result)
205 + ((myDatabaseName != null) ? myDatabaseName.hashCode() : 3);
206 return result;
207 }
208
209 /**
210 * {@inheritDoc}
211 * <p>
212 * Overridden to return a JSON like representation of the
213 * {@link DocumentReference}.
214 * </p>
215 */
216 @Override
217 public String toString() {
218 final StringBuilder builder = new StringBuilder("{ '");
219
220 builder.append(COLLECTION_FIELD_NAME);
221 builder.append("' : '");
222 builder.append(myCollectionName);
223 builder.append("', ");
224
225 builder.append(myId.withName(ID_FIELD_NAME));
226
227 if (myDatabaseName != null) {
228 builder.append(", '");
229 builder.append(DATABASE_FIELD_NAME);
230 builder.append("' : '");
231 builder.append(myDatabaseName);
232 builder.append("'");
233 }
234
235 builder.append(" }");
236
237 return builder.toString();
238 }
239
240 /**
241 * Does a null safe equals comparison.
242 *
243 * @param rhs
244 * The right-hand-side of the comparison.
245 * @param lhs
246 * The left-hand-side of the comparison.
247 * @return True if the rhs equals the lhs. Note: nullSafeEquals(null, null)
248 * returns true.
249 */
250 protected boolean nullSafeEquals(final Object rhs, final Object lhs) {
251 return (rhs == lhs) || ((rhs != null) && rhs.equals(lhs));
252 }
253 }