001: // SSIStream.java
002: // $Id: SSIStream.java,v 1.20 2000/08/16 21:37:46 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.ssi;
007:
008: import java.io.FilterInputStream;
009: import java.io.IOException;
010: import java.io.InputStream;
011: import java.io.PrintStream;
012: import java.io.RandomAccessFile;
013:
014: import org.w3c.jigsaw.http.ClientException;
015: import org.w3c.jigsaw.http.Reply;
016:
017: import org.w3c.jigsaw.ssi.commands.ControlCommandException;
018:
019: /**
020: * This stream concatenates the output streams of each of the segments.
021: * (It absorbs IOExceptions, so that a failure of a segment doesn't
022: * stop the emission).
023: * @author Antonio Ramirez <anto@mit.edu>
024: * @author Benoit Mahe <bmahe@sophia.inria.fr>
025: */
026:
027: class SSIStream extends FilterInputStream {
028:
029: private Segment[] segments;
030: private Reply[] replies;
031: private RandomAccessFile file;
032:
033: private int curSeg = 0;
034: protected boolean cacheValid = true;
035:
036: private boolean nextSegment() {
037: try {
038: if (in != null)
039: in.close();
040: } catch (IOException ex) {
041: // nil
042: }
043: while (curSeg < segments.length) { //-1
044: Segment seg = segments[curSeg];
045: if (seg.isControl()) {
046: if (SSIFrame.debug)
047: System.out.println("@@@@ feeding control segment "
048: + curSeg + ": " + segments[curSeg]);
049: try {
050: curSeg = segments[curSeg].jumpTo();
051: } catch (ControlCommandException ex) {
052: System.out.println(ex.getMessage());
053: ex.printStackTrace();
054: return false;
055: }
056: } else if (!seg.isUnparsed()) {
057: if (!cacheValid) {
058: if (SSIFrame.debug)
059: System.out
060: .println("@@@@ revalidate cache segment "
061: + curSeg
062: + ": "
063: + segments[curSeg]);
064: replies[curSeg] = segments[curSeg].get();
065: } else if (segments[curSeg].needsRevalidate()) {
066: replies[curSeg] = segments[curSeg].get();
067: }
068: if (replies[curSeg] != null) {
069: in = replies[curSeg].openStream();
070: if (in != null) {
071: if (SSIFrame.debug)
072: System.out
073: .println("@@@@ feeding command segment "
074: + curSeg
075: + ": "
076: + segments[curSeg]);
077: curSeg++;
078: return true;
079: } else if (SSIFrame.debug) {
080: System.out
081: .println("@@@@ not feeding command segment "
082: + curSeg
083: + ": "
084: + segments[curSeg]);
085: }
086: }
087: curSeg++;
088: } else {
089: if (SSIFrame.debug)
090: System.out.println("@@@@ feeding Unparsed segment "
091: + curSeg + ": " + segments[curSeg]);
092: try {
093: in = new SegmentInputStream(file, seg.start,
094: seg.end - seg.start);
095: curSeg++;
096: return true;
097: } catch (IOException ex) {
098: // nil
099: }
100: }
101: }
102:
103: in = null;
104: if (SSIFrame.debug)
105: System.out.println("@@@@ no more segments");
106: return false;
107: }
108:
109: public SSIStream(boolean cacheValid, Segment[] segments,
110: Reply[] replies, RandomAccessFile file) throws IOException,
111: ClientException {
112: super ((InputStream) null);
113:
114: this .segments = segments;
115: this .replies = replies;
116: this .file = file;
117: this .cacheValid = cacheValid;
118:
119: nextSegment();
120: }
121:
122: public int read() throws IOException {
123: int data = -1;
124: try {
125: data = in.read();
126: } catch (IOException ex) {
127: if (SSIFrame.debug)
128: System.out.println("@@@@ absorbed exception: "
129: + ex.getMessage());
130: data = -1;
131: } finally {
132: if (data != -1)
133: return data;
134: else {
135: if (!nextSegment())
136: return -1;
137: else
138: return read();
139: }
140: }
141: }
142:
143: public int read(byte b[], int off, int len) throws IOException {
144: int result = -1;
145: try {
146: result = in.read(b, off, len);
147: } catch (IOException ex) {
148: if (SSIFrame.debug)
149: System.out.println("@@@@ absorbed exception: "
150: + ex.getMessage());
151: result = -1;
152: } finally {
153: if (result != -1)
154: return result;
155: else {
156: if (!nextSegment())
157: return -1;
158: else
159: return read(b, off, len);
160: }
161: }
162: }
163:
164: public long skip(long n) throws IOException {
165: return in.skip(n);
166: }
167:
168: public int available() throws IOException {
169: return in.available();
170: }
171:
172: public void close() throws IOException {
173: if (in != null)
174: in.close();
175: file.close();
176: }
177:
178: public synchronized void mark() {
179: // nil
180: }
181:
182: public synchronized void reset() throws IOException {
183: throw new IOException("mark not supported");
184: }
185:
186: public boolean markSupported() {
187: return false;
188: }
189: }
190:
191: /**
192: * Provides an unparsed segment in the input file as an InputStream
193: */
194: class SegmentInputStream extends InputStream {
195:
196: private RandomAccessFile file;
197:
198: private long bytesLeft;
199:
200: SegmentInputStream(RandomAccessFile file, long start, long length)
201: throws IOException {
202: this .file = file;
203: file.seek(start);
204: bytesLeft = length;
205: }
206:
207: public final void close() throws IOException {
208: // nil
209: }
210:
211: public final int read() throws IOException {
212: if (bytesLeft > 0) {
213: bytesLeft--;
214: return file.read();
215: } else
216: return -1;
217: }
218:
219: public final int read(byte b[], int off, int len)
220: throws IOException {
221: if (bytesLeft == 0)
222: return -1;
223: if (len > bytesLeft)
224: len = (int) bytesLeft;
225: file.readFully(b, off, len);
226: bytesLeft -= len;
227: return len;
228: }
229:
230: public final int read(byte b[]) throws IOException {
231: return this .read(b, 0, b.length);
232: }
233:
234: public final void reset() throws IOException {
235: throw new IOException("mark not supported");
236: }
237:
238: public final void mark(int readlimit) {
239: // nil
240: }
241:
242: public final boolean markSupported() {
243: return false;
244: }
245:
246: public final long skip(long n) throws IOException {
247: if (n > bytesLeft)
248: n = bytesLeft;
249: return file.skipBytes((int) n); // hmm...
250: }
251:
252: public final int available() {
253: return (int) bytesLeft;
254: }
255:
256: }
|