/* * Copyright (c) 2008-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mongodb.connection; import com.mongodb.MongoException; import com.mongodb.async.SingleResultCallback; import org.bson.ByteBuf; import org.bson.ByteBufNIO; import org.bson.io.BsonInput; import org.bson.io.ByteBufferBsonInput; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Deque; import java.util.LinkedList; import java.util.List; class TestInternalConnection implements InternalConnection { private static class Interaction { private ResponseBuffers responseBuffers; private RuntimeException receiveException; private RuntimeException sendException; } private final ConnectionDescription description; private final BufferProvider bufferProvider; private final Deque<Interaction> replies; private final List<BsonInput> sent; private boolean opened; private boolean closed; TestInternalConnection(final ServerId serverId) { this.description = new ConnectionDescription(serverId); this.bufferProvider = new SimpleBufferProvider(); this.replies = new LinkedList<Interaction>(); this.sent = new LinkedList<BsonInput>(); } public void enqueueReply(final ResponseBuffers responseBuffers) { Interaction interaction = new Interaction(); interaction.responseBuffers = responseBuffers; replies.add(interaction); } public void enqueueSendMessageException(final RuntimeException e) { Interaction interaction = new Interaction(); interaction.sendException = e; replies.add(interaction); } public void enqueueReceiveMessageException(final RuntimeException e) { Interaction interaction = new Interaction(); interaction.receiveException = e; replies.add(interaction); } public List<BsonInput> getSent() { return sent; } @Override public ConnectionDescription getDescription() { return description; } public void open() { opened = true; } @Override public void openAsync(final SingleResultCallback<Void> callback) { opened = true; callback.onResult(null, null); } @Override public void close() { closed = true; } @Override public boolean opened() { return opened; } @Override public boolean isClosed() { return closed; } @Override public void sendMessage(final List<ByteBuf> byteBuffers, final int lastRequestId) { // repackage all byte buffers into a single byte buffer... int totalSize = 0; for (ByteBuf buf : byteBuffers) { totalSize += buf.remaining(); } ByteBuffer combined = ByteBuffer.allocate(totalSize); for (ByteBuf buf : byteBuffers) { combined.put(buf.array(), 0, buf.remaining()); } combined.flip(); Interaction interaction = replies.getFirst(); if (interaction.responseBuffers != null) { ReplyHeader header = replaceResponseTo(interaction.responseBuffers.getReplyHeader(), lastRequestId); interaction.responseBuffers = (new ResponseBuffers(header, interaction.responseBuffers.getBodyByteBuffer())); sent.add(new ByteBufferBsonInput(new ByteBufNIO(combined))); } else if (interaction.sendException != null) { replies.removeFirst(); throw interaction.sendException; } } private ReplyHeader replaceResponseTo(final ReplyHeader header, final int responseTo) { ByteBuffer headerByteBuffer = ByteBuffer.allocate(36); headerByteBuffer.order(ByteOrder.LITTLE_ENDIAN); headerByteBuffer.putInt(header.getMessageLength()); headerByteBuffer.putInt(header.getRequestId()); headerByteBuffer.putInt(responseTo); headerByteBuffer.putInt(1); headerByteBuffer.putInt(header.getResponseFlags()); headerByteBuffer.putLong(header.getCursorId()); headerByteBuffer.putInt(header.getStartingFrom()); headerByteBuffer.putInt(header.getNumberReturned()); headerByteBuffer.flip(); ByteBufferBsonInput headerInputBuffer = new ByteBufferBsonInput(new ByteBufNIO(headerByteBuffer)); return new ReplyHeader(headerInputBuffer, ConnectionDescription.getDefaultMaxMessageSize()); } @Override public ResponseBuffers receiveMessage(final int responseTo) { if (this.replies.isEmpty()) { throw new MongoException("Test was not setup properly as too many calls to receiveMessage occured."); } Interaction interaction = replies.removeFirst(); if (interaction.responseBuffers != null) { return interaction.responseBuffers; } else { throw interaction.receiveException; } } @Override public void sendMessageAsync(final List<ByteBuf> byteBuffers, final int lastRequestId, final SingleResultCallback<Void> callback) { try { sendMessage(byteBuffers, lastRequestId); callback.onResult(null, null); } catch (RuntimeException e) { callback.onResult(null, e); } } @Override public void receiveMessageAsync(final int responseTo, final SingleResultCallback<ResponseBuffers> callback) { try { ResponseBuffers buffers = receiveMessage(responseTo); callback.onResult(buffers, null); } catch (MongoException ex) { callback.onResult(null, ex); } } @Override public ByteBuf getBuffer(final int size) { return this.bufferProvider.getBuffer(size); } }