1 /*
2 * #%L
3 * MultipleCursorCallback.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.client.callback;
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
26 import java.util.concurrent.atomic.AtomicBoolean;
27
28 import com.allanbank.mongodb.Callback;
29 import com.allanbank.mongodb.MongoDbException;
30 import com.allanbank.mongodb.MongoIterator;
31 import com.allanbank.mongodb.bson.Document;
32 import com.allanbank.mongodb.client.Client;
33 import com.allanbank.mongodb.client.MongoIteratorImpl;
34 import com.allanbank.mongodb.client.message.CursorableMessage;
35 import com.allanbank.mongodb.client.message.Query;
36 import com.allanbank.mongodb.client.message.Reply;
37
38 /**
39 * Callback to convert a {@link CursorableMessage} {@link Reply} into a
40 * collection of {@link MongoIteratorImpl}.
41 *
42 * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
43 * mutated in incompatible ways between any two releases of the driver.
44 * @copyright 2014, Allanbank Consulting, Inc., All Rights Reserved
45 */
46 public final class MultipleCursorCallback extends
47 AbstractReplyCallback<Collection<MongoIterator<Document>>> implements
48 AddressAware {
49
50 /** The server the original request was sent to. */
51 private volatile String myAddress;
52
53 /** The original query. */
54 private final Client myClient;
55
56 /** The original message to start the cursor. */
57 private final CursorableMessage myMessage;
58
59 /** The reply to the query. */
60 private volatile Reply myReply;
61
62 /**
63 * Initially set to false. Set to true for the first of address or reply
64 * being set. The second fails and {@link #trigger() triggers} the callback.
65 */
66 private final AtomicBoolean mySetOther;
67
68 /**
69 * Create a new CursorCallback.
70 *
71 * @param client
72 * The client interface to the server.
73 * @param message
74 * The original query.
75 * @param results
76 * The callback to update once the first set of results are
77 * ready.
78 */
79 public MultipleCursorCallback(final Client client,
80 final CursorableMessage message,
81 final Callback<Collection<MongoIterator<Document>>> results) {
82
83 super(results);
84
85 myClient = client;
86 myMessage = message;
87
88 mySetOther = new AtomicBoolean(false);
89 }
90
91 /**
92 * Returns the server the original request was sent to.
93 *
94 * @return The server the original request was sent to.
95 */
96 public String getAddress() {
97 return myAddress;
98 }
99
100 /**
101 * Sets the value of the server the original request was sent to.
102 *
103 * @param address
104 * The new value for the server the original request was sent to.
105 */
106 @Override
107 public void setAddress(final String address) {
108 myAddress = address;
109 trigger();
110 }
111
112 /**
113 * {@inheritDoc}
114 * <p>
115 * Overridden to add the {@link Query} to the exception.
116 * </p>
117 *
118 * @see AbstractReplyCallback#asError(Reply, int, int, String)
119 */
120 @Override
121 protected MongoDbException asError(final Reply reply, final int okValue,
122 final int errorNumber, final String errorMessage) {
123 return super.asError(reply, okValue, errorNumber, false, errorMessage,
124 myMessage);
125 }
126
127 /**
128 * {@inheritDoc}
129 * <p>
130 * Overridden to construct a {@link MongoIteratorImpl} around the reply.
131 * </p>
132 *
133 * @see AbstractReplyCallback#convert(Reply)
134 */
135 @Override
136 protected Collection<MongoIterator<Document>> convert(final Reply reply)
137 throws MongoDbException {
138 final List<Reply> results = CommandCursorTranslator.translateAll(reply);
139 final List<MongoIterator<Document>> iters = new ArrayList<MongoIterator<Document>>(
140 results.size());
141 for (final Reply r : results) {
142 iters.add(new MongoIteratorImpl(myMessage, myClient, myAddress, r));
143 }
144 return iters;
145 }
146
147 /**
148 * {@inheritDoc}
149 * <p>
150 * Overridden to check if the server address has been set and if so then
151 * pass the converted reply to the {@link #getForwardCallback() forward
152 * callback}. Otherwise the call is dropped.
153 * </p>
154 */
155 @Override
156 protected void handle(final Reply reply) {
157 myReply = reply;
158 trigger();
159 }
160
161 /**
162 * Triggers the callback when the address and reply are set.
163 */
164 private void trigger() {
165 if (!mySetOther.compareAndSet(false, true)) {
166 super.handle(myReply);
167 }
168 }
169 }