jdk/src/share/classes/sun/net/www/MeteredStream.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/net/www/MeteredStream.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,217 @@
+/*
+ * Copyright 1994-2004 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.net.www;
+
+import java.net.URL;
+import java.util.*;
+import java.io.*;
+import sun.net.ProgressSource;
+import sun.net.www.http.ChunkedInputStream;
+
+
+public class MeteredStream extends FilterInputStream {
+
+    // Instance variables.
+    /* if expected != -1, after we've read >= expected, we're "closed" and return -1
+     * from subsequest read() 's
+     */
+    protected boolean closed = false;
+    protected long expected;
+    protected long count = 0;
+    protected long markedCount = 0;
+    protected int markLimit = -1;
+    protected ProgressSource pi;
+
+    public MeteredStream(InputStream is, ProgressSource pi, long expected)
+    {
+        super(is);
+
+        this.pi = pi;
+        this.expected = expected;
+
+        if (pi != null) {
+            pi.updateProgress(0, expected);
+        }
+    }
+
+    private final void justRead(long n) throws IOException   {
+        if (n == -1) {
+
+            /*
+             * don't close automatically when mark is set and is valid;
+             * cannot reset() after close()
+             */
+            if (!isMarked()) {
+                close();
+            }
+            return;
+        }
+
+        count += n;
+
+        /**
+         * If read beyond the markLimit, invalidate the mark
+         */
+        if (count - markedCount > markLimit) {
+            markLimit = -1;
+        }
+
+        if (pi != null)
+            pi.updateProgress(count, expected);
+
+        if (isMarked()) {
+            return;
+        }
+
+        // if expected length is known, we could determine if
+        // read overrun.
+        if (expected > 0)   {
+            if (count >= expected) {
+                close();
+            }
+        }
+    }
+
+    /**
+     * Returns true if the mark is valid, false otherwise
+     */
+    private boolean isMarked() {
+
+        if (markLimit < 0) {
+            return false;
+        }
+
+        // mark is set, but is not valid anymore
+        if (count - markedCount > markLimit) {
+           return false;
+        }
+
+        // mark still holds
+        return true;
+    }
+
+    public synchronized int read() throws java.io.IOException {
+        if (closed) {
+            return -1;
+        }
+        int c = in.read();
+        if (c != -1) {
+            justRead(1);
+        } else {
+            justRead(c);
+        }
+        return c;
+    }
+
+    public synchronized int read(byte b[], int off, int len)
+                throws java.io.IOException {
+        if (closed) {
+            return -1;
+        }
+        int n = in.read(b, off, len);
+        justRead(n);
+        return n;
+    }
+
+    public synchronized long skip(long n) throws IOException {
+
+        // REMIND: what does skip do on EOF????
+        if (closed) {
+            return 0;
+        }
+
+        if (in instanceof ChunkedInputStream) {
+            n = in.skip(n);
+        }
+        else {
+            // just skip min(n, num_bytes_left)
+            long min = (n > expected - count) ? expected - count: n;
+            n = in.skip(min);
+        }
+        justRead(n);
+        return n;
+    }
+
+    public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+        if (pi != null)
+            pi.finishTracking();
+
+        closed = true;
+        in.close();
+    }
+
+    public synchronized int available() throws IOException {
+        return closed ? 0: in.available();
+    }
+
+    public synchronized void mark(int readLimit) {
+        if (closed) {
+            return;
+        }
+        super.mark(readLimit);
+
+        /*
+         * mark the count to restore upon reset
+         */
+        markedCount = count;
+        markLimit = readLimit;
+    }
+
+    public synchronized void reset() throws IOException {
+        if (closed) {
+            return;
+        }
+
+        if (!isMarked()) {
+            throw new IOException ("Resetting to an invalid mark");
+        }
+
+        count = markedCount;
+        super.reset();
+    }
+
+    public boolean markSupported() {
+        if (closed) {
+            return false;
+        }
+        return super.markSupported();
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            close();
+            if (pi != null)
+                pi.close();
+        }
+        finally {
+            // Call super class
+            super.finalize();
+        }
+    }
+}