1 /*
2 * #%L
3 * KillCursors.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 java.io.IOException;
23 import java.util.Arrays;
24
25 import com.allanbank.mongodb.ReadPreference;
26 import com.allanbank.mongodb.bson.io.BsonInputStream;
27 import com.allanbank.mongodb.bson.io.BsonOutputStream;
28 import com.allanbank.mongodb.bson.io.BufferingBsonOutputStream;
29 import com.allanbank.mongodb.client.Message;
30 import com.allanbank.mongodb.client.Operation;
31 import com.allanbank.mongodb.error.DocumentToLargeException;
32
33 /**
34 * Message to <a href=
35 * "http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-OPKILLCURSORS"
36 * >killcursor</a>s that a client no longer needs.
37 *
38 * <pre>
39 * <code>
40 * struct {
41 * MsgHeader header; // standard message header
42 * int32 ZERO; // 0 - reserved for future use
43 * int32 numberOfCursorIDs; // number of cursorIDs in message
44 * int64* cursorIDs; // sequence of cursorIDs to close
45 * }
46 * </code>
47 * </pre>
48 *
49 * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
50 * mutated in incompatible ways between any two releases of the driver.
51 * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
52 */
53 public class KillCursors extends AbstractMessage {
54
55 /** The ids of the cursors to be killed. */
56 private final long[] myCursorIds;
57
58 /**
59 * Creates a new KillCursors.
60 *
61 * @param in
62 * The stream to read the kill_cursors message from.
63 * @throws IOException
64 * On a failure reading the kill_cursors message.
65 */
66 public KillCursors(final BsonInputStream in) throws IOException {
67 init(".");
68
69 in.readInt(); // 0 - reserved.
70 final int numberOfCursors = in.readInt();
71 myCursorIds = new long[numberOfCursors];
72 for (int i = 0; i < numberOfCursors; ++i) {
73 myCursorIds[i] = in.readLong();
74 }
75 }
76
77 /**
78 * Creates a new KillCursors.
79 *
80 * @param cursorIds
81 * The ids of the cursors to kill.
82 * @param readPreference
83 * The preferences for which server to send the request.
84 */
85 public KillCursors(final long[] cursorIds,
86 final ReadPreference readPreference) {
87 super("", "", readPreference);
88 myCursorIds = Arrays.copyOf(cursorIds, cursorIds.length);
89 }
90
91 /**
92 * Determines if the passed object is of this same type as this object and
93 * if so that its fields are equal.
94 *
95 * @param object
96 * The object to compare to.
97 *
98 * @see java.lang.Object#equals(java.lang.Object)
99 */
100 @Override
101 public boolean equals(final Object object) {
102 boolean result = false;
103 if (this == object) {
104 result = true;
105 }
106 else if ((object != null) && (getClass() == object.getClass())) {
107 final KillCursors other = (KillCursors) object;
108
109 // Base class fields are always the same ""."".
110 result = Arrays.equals(myCursorIds, other.myCursorIds);
111 }
112 return result;
113 }
114
115 /**
116 * Returns the ids of the cursors to be killed.
117 *
118 * @return The ids of the cursors to be killed.
119 */
120 public long[] getCursorIds() {
121 return Arrays.copyOf(myCursorIds, myCursorIds.length);
122 }
123
124 /**
125 * {@inheritDoc}
126 * <p>
127 * Overridden to return the name of the operation: "KILL_CURSORS".
128 * </p>
129 */
130 @Override
131 public String getOperationName() {
132 return Operation.KILL_CURSORS.name();
133 }
134
135 /**
136 * Computes a reasonable hash code.
137 *
138 * @return The hash code value.
139 */
140 @Override
141 public int hashCode() {
142 int result = 1;
143 result = (31 * result) + super.hashCode();
144 result = (31 * result) + Arrays.hashCode(myCursorIds);
145 return result;
146 }
147
148 /**
149 * {@inheritDoc}
150 * <p>
151 * Overridden to return the size of the {@link KillCursors}.
152 * </p>
153 */
154 @Override
155 public int size() {
156
157 int size = HEADER_SIZE + 8; // See below.
158 // size += 4; // 0 - reserved
159 // size += 4; // number of cursors.
160 size += (8 * myCursorIds.length);
161
162 return size;
163 }
164
165 /**
166 * {@inheritDoc}
167 * <p>
168 * Overrridden to ensure the size of the cursors ids array is not too large.
169 * </p>
170 */
171 @Override
172 public void validateSize(final int maxDocumentSize)
173 throws DocumentToLargeException {
174 if (maxDocumentSize < (myCursorIds.length * 8)) {
175 throw new DocumentToLargeException((myCursorIds.length * 8),
176 maxDocumentSize, null);
177 }
178 }
179
180 /**
181 * {@inheritDoc}
182 * <p>
183 * Overridden to write the kill_cursors message.
184 * </p>
185 *
186 * @see Message#write(int, BsonOutputStream)
187 */
188 @Override
189 public void write(final int messageId, final BsonOutputStream out)
190 throws IOException {
191 int size = HEADER_SIZE;
192 size += 4; // 0 - reserved
193 size += 4; // number of cursors.
194 size += (8 * myCursorIds.length);
195
196 writeHeader(out, messageId, 0, Operation.KILL_CURSORS, size);
197 out.writeInt(0);
198 out.writeInt(myCursorIds.length);
199 for (final long myCursorId : myCursorIds) {
200 out.writeLong(myCursorId);
201 }
202 }
203
204 /**
205 * {@inheritDoc}
206 * <p>
207 * Overridden to write the kill_cursors message.
208 * </p>
209 *
210 * @see Message#write(int, BsonOutputStream)
211 */
212 @Override
213 public void write(final int messageId, final BufferingBsonOutputStream out)
214 throws IOException {
215 final long start = writeHeader(out, messageId, 0,
216 Operation.KILL_CURSORS);
217 out.writeInt(0);
218 out.writeInt(myCursorIds.length);
219 for (final long myCursorId : myCursorIds) {
220 out.writeLong(myCursorId);
221 }
222 finishHeader(out, start);
223
224 out.flushBuffer();
225 }
226 }