/* * Copyright 2013 mnunberg. * * 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 org.couchbase.mock.memcached; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * This class is used for fine-grained output manipulation. It implements * a system of smaller chunks into which responses are buffered. This is used by * the {@link org.couchbase.mock.memcached.MemcachedServer} class to simulate network * slowness. */ public class OutputContext { private List<ByteBuffer> buffers; private final ByteBuffer[] singleArray = new ByteBuffer[1]; /** * Get an array of buffers representing all the active chunks * @return An array of buffers */ public ByteBuffer[] getIov() { if (buffers.size() == 1) { singleArray[0] = buffers.get(0); return singleArray; } return buffers.toArray(new ByteBuffer[buffers.size()]); } /** * Check if there are unsent chunks */ public boolean hasRemaining() { return !buffers.isEmpty(); } /** * Get an OutputBuffer containing a subset of the current one * * @param limit How many bytes should be available * @return a new OutputContext */ public OutputContext getSlice(int limit) { List<ByteBuffer> newBufs = new LinkedList<ByteBuffer>(); ByteBuffer buf = ByteBuffer.allocate(limit); Iterator<ByteBuffer> iter = buffers.iterator(); while (iter.hasNext() && buf.position() < buf.limit()) { ByteBuffer cur = iter.next(); int diff = buf.limit() - buf.position(); if (diff > cur.limit()) { buf.put(cur); iter.remove(); } else { ByteBuffer slice = cur.duplicate(); slice.limit(diff); buf.put(slice); } } return new OutputContext(newBufs); } /** * Indicate that some data has been flushed to the network * @param num ignored for now. This is because each individual {@link java.nio.ByteBuffer} keeps track * of how many of its bytes were sent */ public void updateBytesSent(long num) { Iterator<ByteBuffer> iter = buffers.iterator(); while (iter.hasNext()) { ByteBuffer cur = iter.next(); if (cur.hasRemaining()) { break; } iter.remove(); } } /** * Create a new OuputContext * @param origBufs A list of buffers which should be set as the initial buffers. If empty, additional buffers * will be created as needed */ public OutputContext(List<ByteBuffer> origBufs) { buffers = origBufs; } /** * Truncate the output. This will empty the list of chunks * @return The list of remaining chunks. */ public List<ByteBuffer> releaseRemaining() { List<ByteBuffer> ret = buffers; buffers = null; return ret; } @Override public String toString() { return "IOV: " + buffers.size(); } }