Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / July 2004

Tip: Looking for answers? Try searching our database.

ProgressMonitorInputStream does not work with url.openStream()

Thread view: 
Rex - 28 Jul 2004 16:50 GMT
I've seen posts talking about this in the past but no body has ever
acknowledged a bug or proposed a solution.  What gives?

If you try to download a file from a website in a Java Swing app, the
file comes down but the progress bar doesn't show.  Try the two code
examples below and see.  The first one requires a url to some large
file on the web.  The second requires a large file (update.zip) in the
working directory.

No progress bar here...

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.*;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.ProgressMonitorInputStream;

public class Test {
 public static void main(String[] args) {
   // create a test frame with a "press me" button
   final JFrame f = new JFrame("Sample");
   f.getContentPane().setLayout(new FlowLayout());
   JButton b = new JButton("Press me");
   f.getContentPane().add(b);
   f.pack();

   // set up the file read action
   b.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       // when button is pressed, start a new thread
       //   to read the file. A new thread is needed because we
       //   need to free the GUI update thread to paint the
       //   progress monitor
       new Thread() {
         public void run() {
           try {
             // open the file, wrapping it in a
ProgressMonitorInputStream
             InputStream in = new URL("http://some big web
file").openStream();
             ProgressMonitorInputStream pm =
                 new ProgressMonitorInputStream(f,"Reading the big
file",in);
             // read the file. If it's taking too long, the progress
             //   monitor will appear. The amount of time is roughly
             //   1/100th of the estimated read time (based on how
long
             //   it took to read the first 1/100th of the file.)
             //   Note that by default, the dialog won't appear
unless
             //   the overall estimate is over 2 seconds.
             int c;
             while((c=pm.read()) != -1) {
               // do something
             }
             pm.close(); // needs better error handling, of course...
           }
           catch(Exception ex) {
             ex.printStackTrace();
           }
         }
       }.start();
     }});  
 
   // display the frame
   f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   f.setVisible(true);
 }
}

Progress bar shows here...

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.InputStream;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.ProgressMonitorInputStream;

public class Test {
 public static void main(String[] args) {
   // create a test frame with a "press me" button
   final JFrame f = new JFrame("Sample");
   f.getContentPane().setLayout(new FlowLayout());
   JButton b = new JButton("Press me");
   f.getContentPane().add(b);
   f.pack();

   // set up the file read action
   b.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       // when button is pressed, start a new thread
       //   to read the file. A new thread is needed because we
       //   need to free the GUI update thread to paint the
       //   progress monitor
       new Thread() {
         public void run() {
           try {
             // open the file, wrapping it in a
ProgressMonitorInputStream
             InputStream in = new FileInputStream("update.zip");
             ProgressMonitorInputStream pm =
                 new ProgressMonitorInputStream(f,"Reading the big
file",in);
             // read the file. If it's taking too long, the progress
             //   monitor will appear. The amount of time is roughly
             //   1/100th of the estimated read time (based on how
long
             //   it took to read the first 1/100th of the file.)
             //   Note that by default, the dialog won't appear
unless
             //   the overall estimate is over 2 seconds.
             int c;
             while((c=pm.read()) != -1) {
               // do something
             }
             pm.close(); // needs better error handling, of course...
           }
           catch(Exception ex) {
             ex.printStackTrace();
           }
         }
       }.start();
     }});  
 
   // display the frame
   f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   f.setVisible(true);
 }
}
Thomas Weidenfeller - 29 Jul 2004 11:01 GMT
> If you try to download a file from a website in a Java Swing app, the
> file comes down but the progress bar doesn't show.

I never verified this, but AFAIK the problem is due to the (absence of
meaningful) information delivered by the InputStream.available() method
for the input stream as obtained via a URL.

This is not a fault of the stream. Please be aware that in general the
size of data obtained via a URL is not predictable in advance. With HTTP
1.1 you are supposed to have the size in the HTTP header, but this is
the exception (URL connections need not use HTTP, and not HTTP 1.1). You
typically simply don't get any information about the size.

The ProgressMonitorInputStream tries to get this value from the stream
once, and provides it as the he maximum value for the progress bar to
the ProgressMonitor. The progress monitor is closed if this value is
reached, or never opened if this value is reached before it initially
opened.

ProgressMonitorInputStream assumes a maximum value of 0 if it can't get
the data from the input stream. This means, the dialog will never open.

There isn't much you can do to fix this. If you don't get the size,
ProgressMonitor is simply the wrong class to use. You have to write your
own dialog, using an indeterminate progress bar. ProgressMonitor can't
be reused in a meaningful way for this, since you don't get access to
its internal progress bar and JDialog. IMHO ProgressMonitor has a rather
stupid design.

If you like, you can try to submit a bug report to Sun (maybe they still
have a few).

/Thomas
William Krick - 29 Jul 2004 17:16 GMT
> There isn't much you can do to fix this. If you don't get the size,
> ProgressMonitor is simply the wrong class to use. You have to write your
[quoted text clipped - 4 lines]
>
> /Thomas

I have submitted this to Sun as a bug.
There is a work around for this problem.

You need to open a URLConnection and query for content length.
Then you need to set the max file size in the progress monitor.
See my example below...

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;

public class Test {

 public static void main(String[] args) {
   final boolean ENABLE_WORK_AROUND = true;
   final JFrame f = new JFrame("Sample");
   JButton b = new JButton("Press me");
   b.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       new Thread() {
         public void run() {
           try {
             // replace URL below with a real URL to a large file
             URL url = new URL("http://www.example.com/bigfile.zip");
             InputStream in = url.openStream();
             System.out.println("input stream reported bytes available: " +
                                in.available());
             ProgressMonitorInputStream pm = new ProgressMonitorInputStream(f,
                 "Reading the big file", in);

             if (ENABLE_WORK_AROUND) {
               int fileSize = url.openConnection().getContentLength();
               System.out.println("actual file size: " + fileSize);
               pm.getProgressMonitor().setMaximum(fileSize);
             }

             int c;
             while ( (c = pm.read()) != -1) {
               // do stuff here
             }
             pm.close();
           }
           catch (Exception ex) {
             ex.printStackTrace();
           }
         }
       }.start();
     }
   });
   f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   f.getContentPane().setLayout(new FlowLayout());
   f.getContentPane().add(b);
   f.pack();
   f.setVisible(true);
 }
}
Thomas Weidenfeller - 30 Jul 2004 07:42 GMT
> You need to open a URLConnection and query for content length.
> Then you need to set the max file size in the progress monitor.

But this only works if there is a content length in the HTTP header.
Which is not guaranteed. So you in order to solve the general case you
still need a fallback if you don't get the size. Then the only thing to
use is an indeterminate progress bar.

/Thomas


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.