src/core/net/sf/basedb/util/InputStreamTracker.java

Code
Comments
Other
Rev Date Author Line
3510 19 Jun 07 nicklas 1 /**
3510 19 Jun 07 nicklas 2   $Id$
3510 19 Jun 07 nicklas 3
3675 16 Aug 07 jari 4   Copyright (C) 2007 Nicklas Nordborg
3510 19 Jun 07 nicklas 5
3510 19 Jun 07 nicklas 6   This file is part of BASE - BioArray Software Environment.
3510 19 Jun 07 nicklas 7   Available at http://base.thep.lu.se/
3510 19 Jun 07 nicklas 8
3510 19 Jun 07 nicklas 9   BASE is free software; you can redistribute it and/or
3510 19 Jun 07 nicklas 10   modify it under the terms of the GNU General Public License
4479 05 Sep 08 jari 11   as published by the Free Software Foundation; either version 3
3510 19 Jun 07 nicklas 12   of the License, or (at your option) any later version.
3510 19 Jun 07 nicklas 13
3510 19 Jun 07 nicklas 14   BASE is distributed in the hope that it will be useful,
3510 19 Jun 07 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
3510 19 Jun 07 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3510 19 Jun 07 nicklas 17   GNU General Public License for more details.
3510 19 Jun 07 nicklas 18
3510 19 Jun 07 nicklas 19   You should have received a copy of the GNU General Public License
4515 11 Sep 08 jari 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
3510 19 Jun 07 nicklas 21 */
3510 19 Jun 07 nicklas 22 package net.sf.basedb.util;
3510 19 Jun 07 nicklas 23
3510 19 Jun 07 nicklas 24 import java.io.IOException;
3510 19 Jun 07 nicklas 25 import java.io.InputStream;
3510 19 Jun 07 nicklas 26
3510 19 Jun 07 nicklas 27 /**
3510 19 Jun 07 nicklas 28   This class is used to keep track of the number of bytes read from the
3510 19 Jun 07 nicklas 29   underlying input stream. This is very useful for code that needs to 
3510 19 Jun 07 nicklas 30   reporter progress but are having difficulties to know the number of
3510 19 Jun 07 nicklas 31   processed bytes.
3510 19 Jun 07 nicklas 32
3510 19 Jun 07 nicklas 33   @author nicklas
3510 19 Jun 07 nicklas 34   @version 2.4
3510 19 Jun 07 nicklas 35   @base.modified $Date$
3510 19 Jun 07 nicklas 36 */
3510 19 Jun 07 nicklas 37 public class InputStreamTracker
3510 19 Jun 07 nicklas 38   extends InputStream
3510 19 Jun 07 nicklas 39 {
3510 19 Jun 07 nicklas 40
3510 19 Jun 07 nicklas 41   /**
3510 19 Jun 07 nicklas 42     The source input stream to read from.
3510 19 Jun 07 nicklas 43   */
3510 19 Jun 07 nicklas 44   private final InputStream in;
3510 19 Jun 07 nicklas 45   
3510 19 Jun 07 nicklas 46   /**
7889 04 Dec 20 nicklas 47     A scale factor to apply when counting bytes.
7889 04 Dec 20 nicklas 48   */
7889 04 Dec 20 nicklas 49   private final ScaleFactor scaleFactor;
7889 04 Dec 20 nicklas 50   
7889 04 Dec 20 nicklas 51   /**
3510 19 Jun 07 nicklas 52     The number of bytes that has been read from the underlying 
3510 19 Jun 07 nicklas 53     input stream so far.
3510 19 Jun 07 nicklas 54   */
3510 19 Jun 07 nicklas 55   private long numRead;
3510 19 Jun 07 nicklas 56   
3510 19 Jun 07 nicklas 57   /**
3510 19 Jun 07 nicklas 58     The number of bytes that had been read when {@link #mark(int)}
3510 19 Jun 07 nicklas 59     was called.
3510 19 Jun 07 nicklas 60   */
3510 19 Jun 07 nicklas 61   private long numReadAtMark;
3510 19 Jun 07 nicklas 62   
3510 19 Jun 07 nicklas 63   /**
3510 19 Jun 07 nicklas 64     Create a new input stream tracker.
3510 19 Jun 07 nicklas 65     @param in The input stream to read from
3510 19 Jun 07 nicklas 66   */
3510 19 Jun 07 nicklas 67   public InputStreamTracker(InputStream in)
3510 19 Jun 07 nicklas 68   {
7889 04 Dec 20 nicklas 69     this(in, null);
7889 04 Dec 20 nicklas 70   }
7889 04 Dec 20 nicklas 71   /**
7889 04 Dec 20 nicklas 72     Create a new input stream tracker.
7889 04 Dec 20 nicklas 73     @param in The input stream to read from
7889 04 Dec 20 nicklas 74     @param scaleFactor A scale factor to apply when counting bytes
7889 04 Dec 20 nicklas 75     @since 3.17.1
7889 04 Dec 20 nicklas 76   */
7889 04 Dec 20 nicklas 77   public InputStreamTracker(InputStream in, ScaleFactor scaleFactor)
7889 04 Dec 20 nicklas 78   {
3510 19 Jun 07 nicklas 79     if (in == null) throw new NullPointerException("in");
3510 19 Jun 07 nicklas 80     this.in = in;
7889 04 Dec 20 nicklas 81     this.scaleFactor = scaleFactor == null ? new IdentityScaleFactor() : scaleFactor;
3510 19 Jun 07 nicklas 82   }
3510 19 Jun 07 nicklas 83   /*
3510 19 Jun 07 nicklas 84     From the InputStream class
3510 19 Jun 07 nicklas 85     -------------------------------------------
3510 19 Jun 07 nicklas 86   */
3510 19 Jun 07 nicklas 87   @Override
3510 19 Jun 07 nicklas 88   public int available() 
3510 19 Jun 07 nicklas 89     throws IOException
3510 19 Jun 07 nicklas 90   {
3510 19 Jun 07 nicklas 91     return in.available();
3510 19 Jun 07 nicklas 92   }
3510 19 Jun 07 nicklas 93   @Override
3510 19 Jun 07 nicklas 94   public void close() 
3510 19 Jun 07 nicklas 95     throws IOException
3510 19 Jun 07 nicklas 96   {
3510 19 Jun 07 nicklas 97     in.close();
3510 19 Jun 07 nicklas 98   }
3510 19 Jun 07 nicklas 99   @Override
3510 19 Jun 07 nicklas 100   public synchronized void mark(int readlimit)
3510 19 Jun 07 nicklas 101   {
3510 19 Jun 07 nicklas 102     in.mark(readlimit);
3510 19 Jun 07 nicklas 103     this.numReadAtMark = numRead;
3510 19 Jun 07 nicklas 104   }
3510 19 Jun 07 nicklas 105   @Override
3510 19 Jun 07 nicklas 106   public boolean markSupported()
3510 19 Jun 07 nicklas 107   {
3510 19 Jun 07 nicklas 108     return in.markSupported();
3510 19 Jun 07 nicklas 109   }
3510 19 Jun 07 nicklas 110   @Override
3510 19 Jun 07 nicklas 111   public int read() 
3510 19 Jun 07 nicklas 112     throws IOException
3510 19 Jun 07 nicklas 113   {
3510 19 Jun 07 nicklas 114     int result = in.read();
3510 19 Jun 07 nicklas 115     if (result != -1) ++numRead;
3510 19 Jun 07 nicklas 116     return result;
3510 19 Jun 07 nicklas 117   }
3510 19 Jun 07 nicklas 118   @Override
3510 19 Jun 07 nicklas 119   public int read(byte[] b, int off, int len) 
3510 19 Jun 07 nicklas 120     throws IOException
3510 19 Jun 07 nicklas 121   {
3510 19 Jun 07 nicklas 122     int result = in.read(b, off, len);
3510 19 Jun 07 nicklas 123     if (result > 0) numRead += result;
3510 19 Jun 07 nicklas 124     return result;
3510 19 Jun 07 nicklas 125   }
3510 19 Jun 07 nicklas 126   @Override
3510 19 Jun 07 nicklas 127   public int read(byte[] b) 
3510 19 Jun 07 nicklas 128     throws IOException
3510 19 Jun 07 nicklas 129   {
3510 19 Jun 07 nicklas 130     return read(b, 0, b.length);
3510 19 Jun 07 nicklas 131   }
3510 19 Jun 07 nicklas 132   @Override
3510 19 Jun 07 nicklas 133   public synchronized void reset() 
3510 19 Jun 07 nicklas 134     throws IOException
3510 19 Jun 07 nicklas 135   {
3510 19 Jun 07 nicklas 136     in.reset();
3510 19 Jun 07 nicklas 137     numRead = numReadAtMark;
3510 19 Jun 07 nicklas 138   }
3510 19 Jun 07 nicklas 139   @Override
3510 19 Jun 07 nicklas 140   public long skip(long n)
3510 19 Jun 07 nicklas 141     throws IOException
3510 19 Jun 07 nicklas 142   {
3510 19 Jun 07 nicklas 143     long result = in.skip(n);
3510 19 Jun 07 nicklas 144     if (result > 0) numRead += result;
3510 19 Jun 07 nicklas 145     return result;
3510 19 Jun 07 nicklas 146   }
3510 19 Jun 07 nicklas 147   // -------------------------------------------
3510 19 Jun 07 nicklas 148
3510 19 Jun 07 nicklas 149   /**
3510 19 Jun 07 nicklas 150     Get the number of bytes read or skipped from the input stream.
3510 19 Jun 07 nicklas 151     If the underlying stream supports {@link #reset()} this will also
3510 19 Jun 07 nicklas 152     reset the number of read bytes to the latest {@link #mark(int)}
3510 19 Jun 07 nicklas 153     position.
3510 19 Jun 07 nicklas 154     @return The number of bytes that has been read so far
3510 19 Jun 07 nicklas 155   */
3510 19 Jun 07 nicklas 156   public long getNumRead()
3510 19 Jun 07 nicklas 157   {
7889 04 Dec 20 nicklas 158     return scaleFactor.scale(numRead);
3510 19 Jun 07 nicklas 159   }
3510 19 Jun 07 nicklas 160
7889 04 Dec 20 nicklas 161   /**
7889 04 Dec 20 nicklas 162     A scale factor can be used to match number of read bytes to something
7889 04 Dec 20 nicklas 163     that better resembles actual progress.
7889 04 Dec 20 nicklas 164     @since 3.17.1
7889 04 Dec 20 nicklas 165   */
7889 04 Dec 20 nicklas 166   public static interface ScaleFactor
7889 04 Dec 20 nicklas 167   {
7889 04 Dec 20 nicklas 168     public long scale(long numRead);
7889 04 Dec 20 nicklas 169   }
7889 04 Dec 20 nicklas 170   
7889 04 Dec 20 nicklas 171   /**
7889 04 Dec 20 nicklas 172     Do not scale number of bytes.
7889 04 Dec 20 nicklas 173   */
7889 04 Dec 20 nicklas 174   public static class IdentityScaleFactor
7889 04 Dec 20 nicklas 175     implements ScaleFactor
7889 04 Dec 20 nicklas 176   {
7889 04 Dec 20 nicklas 177     @Override
7889 04 Dec 20 nicklas 178     public long scale(long numRead)
7889 04 Dec 20 nicklas 179     {
7889 04 Dec 20 nicklas 180       return numRead;
7889 04 Dec 20 nicklas 181     }
7889 04 Dec 20 nicklas 182   }
7889 04 Dec 20 nicklas 183   
7889 04 Dec 20 nicklas 184   /**
7889 04 Dec 20 nicklas 185     Apply a linear scale factor so that when we have read N actual bytes
7889 04 Dec 20 nicklas 186     the getNumRead() method return N*scale bytes.
7889 04 Dec 20 nicklas 187   */
7889 04 Dec 20 nicklas 188   public static class LinearScaleFactor
7889 04 Dec 20 nicklas 189     implements ScaleFactor
7889 04 Dec 20 nicklas 190   {
7889 04 Dec 20 nicklas 191     private final float scale;
7889 04 Dec 20 nicklas 192     public LinearScaleFactor(float scale)
7889 04 Dec 20 nicklas 193     {
7889 04 Dec 20 nicklas 194       this.scale = scale;
7889 04 Dec 20 nicklas 195     }
7889 04 Dec 20 nicklas 196     
7889 04 Dec 20 nicklas 197     @Override
7889 04 Dec 20 nicklas 198     public long scale(long numRead)
7889 04 Dec 20 nicklas 199     {
7889 04 Dec 20 nicklas 200       return (long)(scale * numRead);
7889 04 Dec 20 nicklas 201     }
7889 04 Dec 20 nicklas 202   }
7889 04 Dec 20 nicklas 203   
7889 04 Dec 20 nicklas 204   /**
7889 04 Dec 20 nicklas 205     Apply a curved scale factor that has a max upper limit. To begin
7889 04 Dec 20 nicklas 206     with each byte is counted as 1, but the the more bytes that are read
7889 04 Dec 20 nicklas 207      the scale factor is changed along curved path so that we get closer
7889 04 Dec 20 nicklas 208     and closer to the max limit but never over.
7889 04 Dec 20 nicklas 209   */
7889 04 Dec 20 nicklas 210   public static class CurvedScaleFactor
7889 04 Dec 20 nicklas 211     implements ScaleFactor
7889 04 Dec 20 nicklas 212   {
7889 04 Dec 20 nicklas 213     private final double max;
7889 04 Dec 20 nicklas 214     public CurvedScaleFactor(long max)
7889 04 Dec 20 nicklas 215     {
7889 04 Dec 20 nicklas 216       this.max = max;
7889 04 Dec 20 nicklas 217     }
7889 04 Dec 20 nicklas 218     
7889 04 Dec 20 nicklas 219     @Override
7889 04 Dec 20 nicklas 220     public long scale(long numRead)
7889 04 Dec 20 nicklas 221     {
7889 04 Dec 20 nicklas 222       return (long)(max * -Math.expm1(-numRead/max));
7889 04 Dec 20 nicklas 223     }
7889 04 Dec 20 nicklas 224   }
3510 19 Jun 07 nicklas 225 }