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 */ 022package org.granite.gravity.tomcat; 023 024import java.io.IOException; 025import java.io.InputStream; 026 027/** 028 * An unsynchronized input/output byte buffer that avoids useless byte array copies. 029 * 030 * @author Franck 031 */ 032public 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}