001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.gravity.jbossweb;
023
024 import java.io.IOException;
025 import java.io.InputStream;
026
027 /**
028 * An unsynchronized input/output byte buffer that avoids useless byte array copies.
029 *
030 * @author Franck
031 */
032 public class ByteArrayCometIO extends InputStream implements CometIO {
033
034 private static final byte[] BYTES_0 = new byte[0];
035
036 protected final int initialCapacity;
037 protected byte buf[] = BYTES_0;
038 protected int pos = 0;
039 protected int mark = 0;
040 protected int count = 0;
041
042 public ByteArrayCometIO() {
043 this(2048);
044 }
045
046 public ByteArrayCometIO(int initialCapacity) {
047 if (initialCapacity < 1)
048 throw new IllegalArgumentException("initialCapacity must be > 1: " + initialCapacity);
049 this.initialCapacity = initialCapacity;
050 }
051
052 public int readFully(InputStream is) throws IOException {
053 try {
054 int b = -1;
055
056 while ((b = is.read()) != -1) {
057 if (count + 1 >= buf.length) {
058 if (buf.length > 0) {
059 byte[] tmp = new byte[buf.length << 1];
060 System.arraycopy(buf, 0, tmp, 0, buf.length);
061 buf = tmp;
062 }
063 else
064 buf = new byte[initialCapacity];
065 }
066 buf[count++] = (byte)b;
067 }
068
069 return count;
070 }
071 finally {
072 is.close();
073 }
074 }
075
076 public boolean readAvailable(InputStream is) throws IOException {
077 boolean eof = false;
078
079 try {
080 int available = -1;
081 while ((available = is.available()) > 0) {
082
083 if (count > 0) {
084 byte[] newBytes = new byte[available + count + 1];
085 System.arraycopy(buf, 0, newBytes, 0, count);
086 buf = newBytes;
087 }
088 else
089 buf = new byte[available + 1];
090
091 if (is.read(buf, count, available) != available)
092 throw new IOException("Could not read available bytes: " + available);
093
094 count += available;
095 }
096
097 int b = is.read();
098 if (b == -1) {
099 eof = true;
100 return false;
101 }
102
103 buf[buf.length - 1] = (byte)b;
104 count++;
105
106 return true;
107 }
108 finally {
109 if (eof)
110 is.close();
111 }
112 }
113
114 public InputStream getInputStream() throws IOException {
115 return this;
116 }
117
118 @Override
119 public int read() throws IOException {
120 return (pos < count) ? (buf[pos++] & 0xff) : -1;
121 }
122
123 @Override
124 public int read(byte b[], int off, int len) {
125 if (b == null)
126 throw new NullPointerException();
127
128 if (off < 0 || len < 0 || len > b.length - off)
129 throw new IndexOutOfBoundsException();
130
131 if (pos >= count)
132 return -1;
133
134 if (pos + len > count)
135 len = count - pos;
136
137 if (len <= 0)
138 return 0;
139
140 System.arraycopy(buf, pos, b, off, len);
141 pos += len;
142 return len;
143 }
144
145 @Override
146 public long skip(long n) {
147 if (pos + n > count)
148 n = count - pos;
149
150 if (n < 0)
151 return 0;
152
153 pos += n;
154 return n;
155 }
156
157 @Override
158 public int available() {
159 return count - pos;
160 }
161
162 @Override
163 public boolean markSupported() {
164 return true;
165 }
166
167 @Override
168 public void mark(int readAheadLimit) {
169 mark = pos;
170 }
171
172 @Override
173 public void reset() {
174 pos = mark;
175 }
176
177 @Override
178 public void close() throws IOException {
179 }
180 }