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 }