001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package com.sun.svg.util;
033:
034: import java.io.IOException;
035: import java.io.InputStream;
036:
037: /**
038: * The <code>ProgressInputStream</code> class provides a way to notify the
039: * application of progress when loading a resource, given an expected resource
040: * size.
041: *
042: */
043: public class ProgressiveInputStream extends InputStream {
044: public interface Listener {
045: /**
046: * Notifies the listener of the progress in reading the input stream
047: * content.
048: *
049: * @param progress the current estimated progress, as a penetration factor in the [0,1] interval.
050: */
051: public void streamProgress(float progress);
052: }
053:
054: /**
055: * The proxied InputStream instance.
056: */
057: private InputStream pis;
058:
059: /**
060: * The estimated input stream length.
061: */
062: private float lengthEstimate;
063:
064: /**
065: * The associated listener instance.
066: */
067: private Listener listener;
068:
069: /**
070: * The current byteCount.
071: */
072: private float byteCount;
073:
074: /**
075: * The last time a notification was sent.
076: */
077: private long lastNotification;
078:
079: private static final long MIN_NOTIFICATION_LENGTH = 0;
080:
081: /**
082: * Creates a new instance of ProgressiveInputStream
083: * @param pis the proxied <code>InputStream</code> instance. Should not be null
084: * @param lengthEstimate the anticipated input stream length. Should be strictly positive.
085: * @param listener the ProgressiveInputStream.Listener instance to notify when the input
086: * stream has been fully loaded.
087: */
088: public ProgressiveInputStream(final InputStream pis,
089: final int lengthEstimate, final Listener listener) {
090: if (pis == null) {
091: throw new NullPointerException();
092: }
093:
094: if (lengthEstimate <= 0 || listener == null) {
095: throw new IllegalArgumentException();
096: }
097:
098: this .pis = pis;
099: this .lengthEstimate = lengthEstimate;
100: this .listener = listener;
101:
102: // Initial notification.
103: lastNotification = System.currentTimeMillis();
104: listener.streamProgress(0);
105: }
106:
107: public final int read() throws IOException {
108: int r = pis.read();
109:
110: if (r == -1) {
111: // The end of the stream has been reached.
112: listener.streamProgress(1);
113: } else {
114: byteCount++;
115: long t = System.currentTimeMillis();
116: if ((t - lastNotification) >= MIN_NOTIFICATION_LENGTH) {
117: listener.streamProgress(byteCount / lengthEstimate);
118: lastNotification = t;
119: }
120: }
121:
122: return r;
123: }
124:
125: public int read(byte[] b, int off, int len) throws IOException {
126: int n = pis.read(b, off, len);
127:
128: if (n == -1) {
129: // The end of the stream has been reached.
130: listener.streamProgress(1);
131: } else {
132: byteCount += n;
133: long t = System.currentTimeMillis();
134: if ((t - lastNotification) >= MIN_NOTIFICATION_LENGTH) {
135: listener.streamProgress(byteCount / lengthEstimate);
136: lastNotification = t;
137: }
138: }
139:
140: return n;
141: }
142:
143: public int available() throws IOException {
144: return pis.available();
145: }
146:
147: public void close() throws IOException {
148: pis.close();
149: }
150:
151: public void mark(int readlimit) {
152: pis.mark(readlimit);
153: }
154:
155: public boolean markSupported() {
156: return pis.markSupported();
157: }
158:
159: public void reset() throws IOException {
160: pis.reset();
161: }
162:
163: public long skip(long n) throws IOException {
164: return pis.skip(n);
165: }
166: }
|