001 /**
002 * Copyright (C) 2009-2013 Barchart, Inc. <http://www.barchart.com/>
003 *
004 * All rights reserved. Licensed under the OSI BSD License.
005 *
006 * http://www.opensource.org/licenses/bsd-license.php
007 */
008 package com.barchart.udt.nio;
009
010 import java.io.IOException;
011 import java.io.InputStream;
012 import java.nio.ByteBuffer;
013 import java.nio.channels.IllegalBlockingModeException;
014
015 /**
016 * {@link InputStream} implementation for UDT sockets.
017 */
018 public class NioInputStreamUDT extends InputStream {
019
020 protected final SocketChannelUDT channel;
021
022 /**
023 * Creates a new input stream for the specified channel.
024 *
025 * @param channel
026 * The UDT socket channel.
027 */
028 protected NioInputStreamUDT(final SocketChannelUDT channel) {
029 if (channel == null) {
030 throw new NullPointerException("channel == null");
031 }
032 if (!channel.isBlocking()) {
033 throw new IllegalBlockingModeException();
034 }
035 this.channel = channel;
036 }
037
038 @Override
039 public int read() throws IOException {
040
041 /*
042 * Here's the contract from the JavaDoc on this for SocketChannel:
043 *
044 * A read operation might not fill the buffer, and in fact it might not
045 * read any bytes at all. Whether or not it does so depends upon the
046 * nature and state of the channel. A socket channel in non-blocking
047 * mode, for example, cannot read any more bytes than are immediately
048 * available from the socket's input buffer; similarly, a file channel
049 * cannot read any more bytes than remain in the file. It is guaranteed,
050 * however, that if a channel is in blocking mode and there is at least
051 * one byte remaining in the buffer then this method will block until at
052 * least one byte is read.
053 *
054 * Long story short: This UDT InputStream should only ever be created
055 * when the SocketChannel's in blocking mode, and when it's in blocking
056 * mode the SocketChannel read call below will block just like we need
057 * it too.
058 */
059
060 final byte[] data = new byte[1];
061 read(data);
062 return data[0];
063 }
064
065 @Override
066 public int read(final byte[] bytes) throws IOException {
067 return read(bytes, 0, bytes.length);
068 }
069
070 @Override
071 public int read(final byte[] bytes, final int off, final int len)
072 throws IOException {
073
074 if (len > bytes.length - off) {
075 throw new IndexOutOfBoundsException("len > bytes.length - off");
076 }
077
078 final ByteBuffer buffer = ByteBuffer.wrap(bytes);
079 buffer.position(off);
080 buffer.limit(off + len);
081
082 final int read = channel.read(buffer);
083 return read;
084 }
085
086 @Override
087 public long skip(final long n) throws IOException {
088
089 final ByteBuffer buffer = ByteBuffer.allocateDirect(32768);
090 long remaining = n;
091
092 while (remaining > 0) {
093
094 buffer.limit((int) Math.min(remaining, buffer.capacity()));
095 final int ret = channel.read(buffer);
096
097 if (ret <= 0)
098 break;
099
100 remaining -= ret;
101 buffer.rewind();
102 }
103
104 return n - remaining;
105 }
106
107 @Override
108 public int available() throws IOException {
109 // This is the default InputStream return value.
110 // The java/net/SocketInputStream.java implementation delegates to
111 // the native implementation, which returns 0 on at least some OSes.
112 return 0;
113 }
114
115 @Override
116 public void close() throws IOException {
117 channel.close();
118 }
119
120 @Override
121 public void mark(final int readlimit) {
122 throw new UnsupportedOperationException("mark not supported");
123 }
124
125 @Override
126 public void reset() throws IOException {
127 throw new UnsupportedOperationException("reset not supported");
128 }
129
130 @Override
131 public boolean markSupported() {
132 return false;
133 }
134
135 }