View Javadoc
1   /*
2    * #%L
3    * AbstractMessage.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.client.message;
21  
22  import com.allanbank.mongodb.ReadPreference;
23  import com.allanbank.mongodb.bson.io.BsonOutputStream;
24  import com.allanbank.mongodb.bson.io.BufferingBsonOutputStream;
25  import com.allanbank.mongodb.client.Message;
26  import com.allanbank.mongodb.client.Operation;
27  import com.allanbank.mongodb.client.VersionRange;
28  
29  /**
30   * Base class for a MongoDB message.
31   * 
32   * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
33   *         mutated in incompatible ways between any two releases of the driver.
34   * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
35   */
36  public abstract class AbstractMessage implements Message {
37  
38      /** The size of a message header. */
39      public static final int HEADER_SIZE = Header.SIZE;
40  
41      /** The name of the collection to operate on. */
42      protected String myCollectionName;
43  
44      /** The name of the database to operate on. */
45      protected String myDatabaseName;
46  
47      /** The details on which servers may be sent the message. */
48      private final ReadPreference myReadPreference;
49  
50      /** The required version of the server to support processing the message. */
51      private final VersionRange myRequiredServerVersionRange;
52  
53      /**
54       * Create a new AbstractMessage.
55       */
56      public AbstractMessage() {
57          myDatabaseName = "";
58          myCollectionName = "";
59          myReadPreference = ReadPreference.PRIMARY;
60          myRequiredServerVersionRange = null;
61      }
62  
63      /**
64       * Create a new AbstractMessage.
65       * 
66       * @param databaseName
67       *            The name of the database.
68       * @param collectionName
69       *            The name of the collection.
70       * @param readPreference
71       *            The preferences for which servers to send the message.
72       */
73      public AbstractMessage(final String databaseName,
74              final String collectionName, final ReadPreference readPreference) {
75          myDatabaseName = databaseName;
76          myCollectionName = collectionName;
77          myReadPreference = readPreference;
78          myRequiredServerVersionRange = null;
79      }
80  
81      /**
82       * Creates a new AbstractMessage.
83       * 
84       * @param databaseName
85       *            The name of the database.
86       * @param collectionName
87       *            The name of the collection.
88       * @param readPreference
89       *            The preferences for which servers to send the message.
90       * @param versionRange
91       *            The required range of versions of the server to support
92       *            processing the message.
93       */
94      public AbstractMessage(final String databaseName,
95              final String collectionName, final ReadPreference readPreference,
96              final VersionRange versionRange) {
97          myDatabaseName = databaseName;
98          myCollectionName = collectionName;
99          myReadPreference = readPreference;
100         myRequiredServerVersionRange = versionRange;
101     }
102 
103     /**
104      * Determines if the passed object is of this same type as this object and
105      * if so that its fields are equal.
106      * 
107      * @param object
108      *            The object to compare to.
109      * 
110      * @see java.lang.Object#equals(java.lang.Object)
111      */
112     @Override
113     public boolean equals(final Object object) {
114         boolean result = false;
115 
116         // This should never return false as derived classes should have
117         // verified.
118         if ((object != null) && (getClass() == object.getClass())) {
119             final AbstractMessage other = (AbstractMessage) object;
120 
121             result = myCollectionName.equals(other.myCollectionName)
122                     && myDatabaseName.equals(other.myDatabaseName)
123                     && myReadPreference.equals(other.myReadPreference);
124         }
125         return result;
126     }
127 
128     /**
129      * Returns the name of the collection.
130      * 
131      * @return The name of the collection.
132      */
133     public String getCollectionName() {
134         return myCollectionName;
135     }
136 
137     /**
138      * Returns the name of the database.
139      * 
140      * @return The name of the database.
141      */
142     @Override
143     public String getDatabaseName() {
144         return myDatabaseName;
145     }
146 
147     /**
148      * {@inheritDoc}
149      * <p>
150      * Returns the message's read preference.
151      * </p>
152      */
153     @Override
154     public ReadPreference getReadPreference() {
155         return myReadPreference;
156     }
157 
158     /**
159      * {@inheritDoc}
160      */
161     @Override
162     public VersionRange getRequiredVersionRange() {
163         return myRequiredServerVersionRange;
164     }
165 
166     /**
167      * Computes a reasonable hash code.
168      * 
169      * @return The hash code value.
170      */
171     @Override
172     public int hashCode() {
173         int result = 1;
174         result = (31 * result) + myCollectionName.hashCode();
175         result = (31 * result) + myDatabaseName.hashCode();
176         result = (31 * result) + myReadPreference.hashCode();
177         return result;
178     }
179 
180     /**
181      * Writes the MsgHeader messageLengthField in the header <tt>stream</tt>.
182      * 
183      * <pre>
184      * <code>
185      * struct MsgHeader {
186      *     int32   messageLength; // total message size, including this
187      *     int32   requestID;     // identifier for this message
188      *     int32   responseTo;    // requestID from the original request
189      *                            //   (used in reponses from db)
190      *     int32   opCode;        // request type - see table below
191      * }
192      * </code>
193      * </pre>
194      * 
195      * @param stream
196      *            The stream to write to.
197      * @param start
198      *            The position of the start of the header for the message.
199      */
200     protected void finishHeader(final BufferingBsonOutputStream stream,
201             final long start) {
202 
203         final long end = stream.getPosition();
204 
205         stream.writeIntAt(start, (int) (end - start));
206     }
207 
208     /**
209      * Initializes the database and collection name from the full database name.
210      * 
211      * @param name
212      *            The full database name.
213      */
214     protected void init(final String name) {
215         final int firstDot = name.indexOf('.');
216         if (firstDot >= 0) {
217             myDatabaseName = name.substring(0, firstDot);
218             myCollectionName = name.substring(firstDot + 1);
219         }
220         else {
221             myDatabaseName = name;
222         }
223     }
224 
225     /**
226      * Writes the MsgHeader to the <tt>stream</tt>.
227      * 
228      * <pre>
229      * <code>
230      * struct MsgHeader {
231      *     int32   messageLength; // total message size, including this
232      *     int32   requestID;     // identifier for this message
233      *     int32   responseTo;    // requestID from the original request
234      *                            //   (used in reponses from db)
235      *     int32   opCode;        // request type - see table below
236      * }
237      * </code>
238      * </pre>
239      * 
240      * @param stream
241      *            The stream to write to.
242      * @param requestId
243      *            The requestID from above.
244      * @param responseTo
245      *            The responseTo from above.
246      * @param op
247      *            The operation for the opCode field.
248      * @param length
249      *            The length of the message including the header.
250      */
251     protected void writeHeader(final BsonOutputStream stream,
252             final int requestId, final int responseTo, final Operation op,
253             final int length) {
254         stream.writeInt(length);
255         stream.writeInt(requestId);
256         stream.writeInt(responseTo);
257         stream.writeInt(op.getCode());
258     }
259 
260     /**
261      * Writes the MsgHeader to the <tt>stream</tt>.
262      * 
263      * <pre>
264      * <code>
265      * struct MsgHeader {
266      *     int32   messageLength; // total message size, including this
267      *     int32   requestID;     // identifier for this message
268      *     int32   responseTo;    // requestID from the original request
269      *                            //   (used in reponses from db)
270      *     int32   opCode;        // request type - see table below
271      * }
272      * </code>
273      * </pre>
274      * 
275      * @param stream
276      *            The stream to write to.
277      * @param requestId
278      *            The requestID from above.
279      * @param responseTo
280      *            The responseTo from above.
281      * @param op
282      *            The operation for the opCode field.
283      * @return The position of the start of the header for the message.
284      */
285     protected long writeHeader(final BufferingBsonOutputStream stream,
286             final int requestId, final int responseTo, final Operation op) {
287 
288         final long start = stream.getPosition();
289 
290         stream.writeInt(0);
291         stream.writeInt(requestId);
292         stream.writeInt(responseTo);
293         stream.writeInt(op.getCode());
294 
295         return start;
296     }
297 
298 }