001: /*
002: * Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.net.www;
027:
028: import java.net.URL;
029: import java.util.*;
030: import java.io.*;
031: import sun.net.ProgressSource;
032: import sun.net.www.http.ChunkedInputStream;
033:
034: public class MeteredStream extends FilterInputStream {
035:
036: // Instance variables.
037: /* if expected != -1, after we've read >= expected, we're "closed" and return -1
038: * from subsequest read() 's
039: */
040: protected boolean closed = false;
041: protected int expected;
042: protected int count = 0;
043: protected int markedCount = 0;
044: protected int markLimit = -1;
045: protected ProgressSource pi;
046:
047: public MeteredStream(InputStream is, ProgressSource pi, int expected) {
048: super (is);
049:
050: this .pi = pi;
051: this .expected = expected;
052:
053: if (pi != null) {
054: pi.updateProgress(0, expected);
055: }
056: }
057:
058: private final void justRead(int n) throws IOException {
059: if (n == -1) {
060:
061: /*
062: * don't close automatically when mark is set and is valid;
063: * cannot reset() after close()
064: */
065: if (!isMarked()) {
066: close();
067: }
068: return;
069: }
070:
071: count += n;
072:
073: /**
074: * If read beyond the markLimit, invalidate the mark
075: */
076: if (count - markedCount > markLimit) {
077: markLimit = -1;
078: }
079:
080: if (pi != null)
081: pi.updateProgress(count, expected);
082:
083: if (isMarked()) {
084: return;
085: }
086:
087: // if expected length is known, we could determine if
088: // read overrun.
089: if (expected > 0) {
090: if (count >= expected) {
091: close();
092: }
093: }
094: }
095:
096: /**
097: * Returns true if the mark is valid, false otherwise
098: */
099: private boolean isMarked() {
100:
101: if (markLimit < 0) {
102: return false;
103: }
104:
105: // mark is set, but is not valid anymore
106: if (count - markedCount > markLimit) {
107: return false;
108: }
109:
110: // mark still holds
111: return true;
112: }
113:
114: public synchronized int read() throws java.io.IOException {
115: if (closed) {
116: return -1;
117: }
118: int c = in.read();
119: if (c != -1) {
120: justRead(1);
121: } else {
122: justRead(c);
123: }
124: return c;
125: }
126:
127: public synchronized int read(byte b[], int off, int len)
128: throws java.io.IOException {
129: if (closed) {
130: return -1;
131: }
132: int n = in.read(b, off, len);
133: justRead(n);
134: return n;
135: }
136:
137: public synchronized long skip(long n) throws IOException {
138:
139: // REMIND: what does skip do on EOF????
140: if (closed) {
141: return 0;
142: }
143:
144: if (in instanceof ChunkedInputStream) {
145: n = in.skip(n);
146: } else {
147: // just skip min(n, num_bytes_left)
148: int min = (n > expected - count) ? expected - count
149: : (int) n;
150: n = in.skip(min);
151: }
152: justRead((int) n);
153: return n;
154: }
155:
156: public void close() throws IOException {
157: if (closed) {
158: return;
159: }
160: if (pi != null)
161: pi.finishTracking();
162:
163: closed = true;
164: in.close();
165: }
166:
167: public synchronized int available() throws IOException {
168: return closed ? 0 : in.available();
169: }
170:
171: public synchronized void mark(int readLimit) {
172: if (closed) {
173: return;
174: }
175: super .mark(readLimit);
176:
177: /*
178: * mark the count to restore upon reset
179: */
180: markedCount = count;
181: markLimit = readLimit;
182: }
183:
184: public synchronized void reset() throws IOException {
185: if (closed) {
186: return;
187: }
188:
189: if (!isMarked()) {
190: throw new IOException("Resetting to an invalid mark");
191: }
192:
193: count = markedCount;
194: super .reset();
195: }
196:
197: public boolean markSupported() {
198: if (closed) {
199: return false;
200: }
201: return super .markSupported();
202: }
203:
204: protected void finalize() throws Throwable {
205: try {
206: close();
207: if (pi != null)
208: pi.close();
209: } finally {
210: // Call super class
211: super.finalize();
212: }
213: }
214: }
|