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