View Javadoc
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 &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) 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 }