001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.data.RememberBytesInputStream
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.raw.data;
023:
024: import org.apache.derby.iapi.services.sanity.SanityManager;
025: import java.io.FilterInputStream;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.OutputStream;
029:
030: /**
031: A FilterInputStream that remembers read or skipped bytes.
032:
033: <P>In record mode this stream remembers all the bytes a
034: caller reads or skips. After reading some bytes this
035: returns a 'replay' stream to re-read them.
036:
037: <P>A caller may call getReplaySteam to get a stream
038: to re-read the the remembered bytes. Any number of calls
039: to getReplayStream are supported.
040:
041: <P>The clear function causes this stream to forget the remembered
042: bytes and re-enter record mode.
043: */
044: public class RememberBytesInputStream extends FilterInputStream {
045: ByteHolder bh;
046: boolean recording = true;
047:
048: // In case of streams (e.g ReaderToUTF8Stream,
049: // RawToBinaryFormatStream) that cannot be re-used
050: // a read on a closed stream will throw an EOFException
051: // hence keep track if the stream is closed or not
052: boolean streamClosed = false;
053:
054: /**
055: Construct a RememberBytesInputStream.
056:
057: @param bh for storing the remembered bytes. (must be
058: in writing mode.
059: */
060: public RememberBytesInputStream(InputStream in, ByteHolder bh) {
061: super (in);
062:
063: if (SanityManager.DEBUG)
064: SanityManager.ASSERT(bh.writingMode());
065:
066: this .bh = bh;
067:
068: }
069:
070: /**
071: @see java.io.InputStream#read
072: @exception IOException thrown on an io error spooling rememberd bytes
073: to backing storage.
074: */
075: public int read() throws IOException {
076: if (SanityManager.DEBUG)
077: SanityManager.ASSERT(recording,
078: "Must be in record mode to perform a read.");
079:
080: int value = -1;
081:
082: if (!streamClosed) {
083: value = super .read();
084: if (value != -1)
085: bh.write(value);
086: else
087: streamClosed = true;
088: }
089:
090: return value;
091: }
092:
093: /**
094: @see java.io.InputStream#read
095: @exception IOException thrown on an io error spooling rememberd bytes
096: to backing storage.
097: */
098: public int read(byte b[], int off, int len) throws IOException {
099: if (SanityManager.DEBUG)
100: SanityManager.ASSERT(recording,
101: "Must be in record mode to perform a read.");
102:
103: if (!streamClosed) {
104: if ((len + off) > b.length)
105: len = b.length - off;
106:
107: len = super .read(b, off, len);
108: if (len > 0)
109: bh.write(b, off, len);
110: else
111: streamClosed = true;
112: } else {
113: return -1;
114: }
115:
116: return len;
117: }
118:
119: /**
120: read len bytes from the input stream, and store it in the byte holder.
121:
122: Note, fillBuf does not return negative values, if there are no
123: bytes to store in the byteholder, it will return 0
124: @exception IOException thrown on an io error spooling rememberd bytes
125: to backing storage.
126: */
127: public long fillBuf(int len) throws IOException {
128:
129: long val = 0;
130:
131: if (!streamClosed) {
132: val = bh.write(this .in, len);
133:
134: // if bh.write returns less than len, then the stream
135: // has reached end of stream. See logic in MemByteHolder.write
136: if (val < len)
137: streamClosed = true;
138: }
139:
140: return val;
141: }
142:
143: /**
144: read len bytes from the byte holder, and write it to the output stream.
145:
146: @exception IOException thrown on an io error spooling rememberd bytes
147: to backing storage.
148: */
149: public int putBuf(OutputStream out, int len) throws IOException {
150: bh.startReading();
151: return bh.read(out, len);
152: }
153:
154: /**
155: @see java.io.InputStream#skip
156: @exception IOException thrown on an io error spooling rememberd bytes
157: to backing storage.
158: */
159: public long skip(long count) throws IOException {
160: if (SanityManager.DEBUG)
161: SanityManager.ASSERT(recording,
162: "Must be in record mode to perform a read.");
163: return bh.write(in, count);
164: }
165:
166: /**
167: Get an input stream for re-reading the remembered bytes.
168: */
169: public InputStream getReplayStream() throws IOException {
170: bh.startReading();
171: recording = false;
172: return new ByteHolderInputStream(bh);
173: }
174:
175: /**
176: Get the byteHolder.
177: */
178: public ByteHolder getByteHolder() throws IOException {
179: return bh;
180: }
181:
182: /**
183: Clear all the remembered bytes. This stream will
184: remember any bytes read after this call.
185: @exception IOException thrown on an io error clearing backing
186: storage.
187: */
188: public void clear() throws IOException {
189: bh.clear();
190: recording = true;
191: }
192:
193: /**
194: Set the InputStream from which this reads.
195:
196: <P>Please note this does not clear remembered
197: bytes.
198: */
199: public void setInput(InputStream in) {
200: this .in = in;
201: streamClosed = false;
202: }
203:
204: /**
205: Return true iff this RememberBytesInputStream is
206: in recording mode.
207: */
208: public boolean recording() {
209: return recording;
210: }
211:
212: /**
213: Return the number of bytes remains in the byteHolder
214: for reading, without setting the write/read mode.
215: */
216: public int available() throws IOException {
217: // may not have set reading to be true, then,
218: // we are getting available in negative numbers.
219: int remainingBytes = bh.available();
220: remainingBytes = remainingBytes > 0 ? remainingBytes : (-1)
221: * remainingBytes;
222: return remainingBytes;
223: }
224:
225: /**
226: Return the number of bytes that have been saved to this byte holder.
227: This result is different from available() as it is unaffected by the
228: current read position on the ByteHolder.
229: */
230: public int numBytesSaved() throws IOException {
231: return (bh.numBytesSaved());
232: }
233:
234: /**
235: remove the remaining bytes in the byteHolder to the beginning
236: set the position to start recording just after these bytes.
237: returns how many bytes was transfered to the beginning.
238: */
239: public int shiftToFront() throws IOException {
240: int bytesShifted = bh.shiftToFront();
241: return bytesShifted;
242: }
243:
244: /**
245: @see java.lang.Object#toString
246: */
247: public String toString() {
248: return "RememberBytesInputStream: " + " recording: "
249: + recording + " " + bh;
250: }
251: }
|