001: package net.matuschek.util;
002:
003: import java.io.FilterInputStream;
004: import java.io.IOException;
005: import java.io.InputStream;
006:
007: /*********************************************
008: Copyright (c) 2001 by Daniel Matuschek
009: *********************************************/
010:
011: /**
012: * A FilterInputStream with a limited bandwith
013: *
014: * This implements an filter for an existing input stream that allows
015: * it to limit the read bandwidth. This can be useful for network
016: * streams that should be limited to a specified bandwidth.
017: *
018: * @author <a href="mailto: daniel@matuschek.net">Daniel Matuschek</a>
019: * @version $id$
020: */
021: public class LimitedBandwidthStream extends FilterInputStream {
022:
023: /** usable bandwidth in bytes/second **/
024: private int bandwidth = 0;
025:
026: /** bandwidth limit will be calculated form the start time **/
027: private boolean isReading = false;
028:
029: /** number of bytes read **/
030: private int count = 0;
031:
032: /** check bandwidth every n bytes **/
033: private static int CHECK_INTERVAL = 100;
034:
035: /** start time **/
036: long starttime = 0;
037:
038: /** used time **/
039: long usedtime = 0;
040:
041: /**
042: * initializes the LimitedBandWidth stream
043: */
044: public LimitedBandwidthStream(InputStream in, int bandwidth)
045: throws IOException {
046: super (in);
047:
048: if (bandwidth > 0) {
049: this .bandwidth = bandwidth;
050: } else {
051: this .bandwidth = 0;
052: }
053:
054: count = 0;
055: }
056:
057: /**
058: * Reads the next byte.
059: *
060: * Reads the next byte of data from this input stream. The value byte
061: * is returned as an int in the range 0 to 255. If no byte is available
062: * because the end of the stream has been reached, the value -1 is
063: * returned. This method blocks until input data is available, the end
064: * of the stream is detected, or an exception is thrown.
065: * If the bandwidth consumption exceeds the defined limit, read will block
066: * until the bandwidth is in the limit again.
067: *
068: * @return the next byte from the stream or -1 if end-of-stream
069: */
070: public int read() throws IOException {
071: long currentBandwidth;
072:
073: if (!isReading) {
074: starttime = System.currentTimeMillis();
075: isReading = true;
076: }
077:
078: // do bandwidth check only if bandwidth
079: if ((bandwidth > 0) && ((count % CHECK_INTERVAL) == 0)) {
080: do {
081: usedtime = System.currentTimeMillis() - starttime;
082: if (usedtime > 0) {
083: currentBandwidth = (count * 1000) / usedtime;
084: } else {
085: currentBandwidth = 0;
086: }
087: if (currentBandwidth > bandwidth) {
088: try {
089: Thread.sleep(100);
090: } catch (InterruptedException e) {
091: }
092: }
093: } while (currentBandwidth > bandwidth);
094: }
095:
096: count++;
097: return super .read();
098: }
099:
100: /**
101: * Shortcut for read(b,0,b.length)
102: *
103: * @see #read(byte[], int, int)
104: */
105: public int read(byte[] b) throws IOException {
106: return read(b, 0, b.length);
107: }
108:
109: /**
110: * Reads a block of bytes from the stream.
111: *
112: * If the bandwith is not limited, it simply used the
113: * read(byte[], int, int) method of the input stream, otherwise it
114: * uses multiple read() request to enforce bandwith limitation (this
115: * is easier to implement using byte reads).
116: *
117: * @return the number of bytes read or -1 at end of stream
118: */
119: public int read(byte[] b, int off, int len) throws IOException {
120: int mycount = 0;
121: int current = 0;
122: // limit bandwidth ?
123: if (bandwidth > 0) {
124: for (int i = off; i < off + len; i++) {
125: current = read();
126: if (current == -1) {
127: return mycount;
128: } else {
129: b[i] = (byte) current;
130: count++;
131: mycount++;
132: }
133: }
134: return mycount;
135: } else {
136: return in.read(b, off, len);
137: }
138: }
139:
140: } // LimitedBandwidthStream
|