In this blog post I would like to show, how you can implement simple monitoring capabilities for standard Java’s
OutputStream. By “monitoring capabilities” I mean ability to find out information like Speed, Estimated Time, Transfered Size, etc. Recently I implemented this for our internal deployment tool (simple Swing-based application written in Scala). After about 30 minutes of googling without much success, I actually tried to think about this and found out how simple it actually is. So I decided to share this with you. Additionally I also want to give you small demonstration of scala-swing which I’m enjoying a lot.
After reading this article you will find out how you can write application like this one:
Creating Stream Filter
In order to get all metrics shown above, we need to know the full size of the file/stream and currently transfered amount of bytes. The full size is easy to find out from outside of the
Stream, especially if you are working with files, but we need to monitor
Stream in order to find out how much bytes are transfered already. Here is an example of such
InputStream, that reports this with specified threshold:
You have probably noticed
ProgressListener. It’s function
Long => Unit which we will discuss next.
In order to show transferred number of bytes, we need to remember it somehow.
ProgressListener function makes just this + calculates another metrics:
What’s interesting about this, is that I do cont define function with function literal like:
(bytes: Long) => Unit. Instead I’m creating a new class that extends
Function1[Long, Unit] - it’s allowed in Scala and sometimes can be very useful. Actually many Scala’s collection classes also making this, so you can get i-th element of the list like this:
myList(i). In my case, it allowed me to have some internal state (
startTime fields) and to parametrize function with some arguments (
tracker) during it’s creation. It’s also possible to use function literal for this and still archive the same results - you just need to use currying and closures in this case. But I find, that it’s more clear and readable to define
ProgressListener as class in this particular case.
You can tweak this algorithm and make it more accurate. For example you can calculate
bps depending on the bytes, that were transferred during last several seconds. Still I think, that this algorithm does it’s job for many use cases.
Now let’s take a look at
Progress case class. It’s purpose is to hold different metrics and format it when needed (formatting can be probably done somewhere else, but I decided to put it here just to keep it simple).
Here you can also find nice utility functions to format size and time.
User Interface With Scala-Swing
Now let’s create simple application that downloads files and shows the progress:
This application throws all downloaded bytes away, so it’s pretty useless, but I hope that it will demonstrate you scala-swing basics.
Hopefully this will also give you some impressions on how easy it is to integrate with Java standard library from Scala. For your convenience I also created gist with all these classes in it, so you can just copy/paste it in your own projects and start playing with it.