All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.schooner.MemCached.SockInputStream Maven / Gradle / Ivy

There is a newer version: 3.3.8
Show newest version
/*******************************************************************************
 * Copyright (c) 2009 Schooner Information Technology, Inc.
 * All rights reserved.
 * 
 * http://www.schoonerinfotech.com/
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
package com.schooner.MemCached;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.BufferUnderflowException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

/**
 * {@link SockInputStream} is a inputstream based on a socket. Due to memcached
 * protocol, we can only read specified length from the socket, you have to set
 * the byte length to read before invoke read.
 * 
 * @author Xingen Wang
 * @since 2.5.0
 * @see InputStream
 */
public final class SockInputStream extends InputStream {
	private SchoonerSockIO sock;
	private int limit;
	private int count = 0;
	private byte b;
	private ByteArrayOutputStream bos = new ByteArrayOutputStream();

	/**
	 * get length of to-be-read.
	 * 
	 * @return length
	 */
	public final int getWillRead() {
		return limit;
	}

	/**
	 * set limited length to read.
	 * 
	 * @param length
	 *            length to set.
	 */
	public final void willRead(int limit) {
		this.limit = limit;
		count = 0;
	}

	/**
	 * Constructor.
	 * 
	 * @param sock
	 *            {@link SchoonerSockIO}, read from this socket.
	 * @param limit
	 *            limited length to read from specified socket.
	 * @throws IOException
	 *             error happened in reading.
	 */
	public SockInputStream(final SchoonerSockIO sock, int limit) throws IOException {
		this.sock = sock;
		willRead(limit);
		sock.readBuf.clear();
		sock.getChannel().read(sock.readBuf);
		sock.readBuf.flip();
	}

	/**
	 * Constructor. Read all buffered bytes in the socket.
	 * 
	 * @param sock
	 *            {@link SchoonerSockIO}, read from this socket.
	 * @throws IOException
	 *             error happened in reading.
	 */
	public SockInputStream(final SchoonerSockIO sock) throws IOException {
		this(sock, sock.readBuf.remaining());
	}

	@Override
	public final int read() throws IOException {
		if (count >= limit) {
			return -1;
		}
		b = 0;
		try {
			b = sock.readBuf.get();
		} catch (BufferUnderflowException e) {
			readFromChannel();
			b = sock.readBuf.get();
		}
		count++;
		/*
		 * a potencial bug for read int or read long.
		 */
		return (b & 0xff);
	}

	/**
	 * read bytes from socket.
	 * 
	 * @throws IOException
	 *             error happened in read.
	 */
	private final void readFromChannel() throws IOException {
		sock.readBuf.clear();
		// sock.getChannel().read(sock.readBuf);
		ReadableByteChannel wrappedChannel = Channels.newChannel(sock.getChannel().socket().getInputStream());
		wrappedChannel.read(sock.readBuf);
		sock.readBuf.flip();
	}

	@Override
	public final int read(byte[] b, int off, int len) throws IOException {
		if (count >= limit) {
			return -1;
		}
		int read = 0;
		int r1 = 0;
		final int remain = limit - count;
		len = len < remain ? len : remain;
		while (len - read > 0) {
			r1 = sock.readBuf.remaining();
			r1 = r1 < len - read ? r1 : len - read;
			sock.readBuf.get(b, off + read, r1);
			if (r1 != len - read)
				readFromChannel();
			read += r1;
		}
		count += len;
		return len;
	}

	/**
	 * get all left bytes from the socket.
	 * 
	 * @return byte array of holding all bytes.
	 * @throws IOException
	 *             error happened in reading.
	 */
	public final byte[] getBuffer() throws IOException {
		byte[] bs = new byte[limit - count];
		read(bs);
		return bs;
	}

	/**
	 * get a line from the socket.
	 * 
	 * @return a line
	 * @throws IOException
	 *             error happend in reading.
	 * @since 2.5.1
	 */
	public final String getLine() throws IOException {
		bos.reset();
		int b;
		while ((b = read()) != -1) {
			bos.write(b);
			if (b == '\n') {
				break;
			}
		}
		return new String(bos.toByteArray());
	}

	@Override
	public int available() throws IOException {
		return sock.readBuf.remaining();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy