/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
package de.cismet.cismap.commons.demo;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.util.Observable;
import javax.swing.ProgressMonitor;
import javax.swing.Timer;
import de.cismet.tools.CismetThreadPool;
/**
* Transfer data from one stream to another, providing a Swing ProgressMonitor to handle notifying the user and allowing
* the user to cancel the transfer. The progress updates every half-second.
*
* <p>Objects of this class also act as Observables, updating their observers after each block of data is transfered,
* and again at the end of the transfer.</p>
*
* @version $Revision$, $Date$
*/
public class ProgressMonitoredDataTransfer extends Observable implements Runnable, ActionListener {
//~ Static fields/initializers ---------------------------------------------
public static final int DELAY = 1;
public static final int BUFSIZ = 1024;
//~ Instance fields --------------------------------------------------------
private InputStream readFrom;
private OutputStream writeTo;
private ProgressMonitor monitor;
private boolean done;
private int max;
private int current;
private Timer mytimer;
private Thread mythread;
private boolean closeWhenDone;
//~ Constructors -----------------------------------------------------------
/**
* Create a progress monitored data transfer.
*
* @param par Parent Swing Window or Frame
* @param from Stream to read data from
* @param to Stream to write data out to
* @param maxtransfer Maximum number of bytes we expect to transfer
* @param message Progress monitor message object (usually String)
* @param close If set, then close the streams at end of transfer
*/
public ProgressMonitoredDataTransfer(final Component par,
final InputStream from,
final OutputStream to,
final int maxtransfer,
final Object message,
final boolean close) {
readFrom = new BufferedInputStream(from);
writeTo = to;
max = maxtransfer;
monitor = new ProgressMonitor(par, message, null, 0, max);
monitor.setMillisToPopup(2 * DELAY);
mythread = new Thread(this, "ProgressMonitoredDataTransfer");
mytimer = new Timer(DELAY, this);
done = false;
closeWhenDone = close;
current = 0;
CismetThreadPool.execute(mythread);
mytimer.start();
}
//~ Methods ----------------------------------------------------------------
/**
* Handle timer actions.
*
* @param e DOCUMENT ME!
*/
@Override
public void actionPerformed(final ActionEvent e) {
if (isDone()) {
// if the transfer is done, close the monitor
monitor.close();
mytimer.stop();
} else if (monitor.isCanceled()) {
// if the user hits cancel, then interrupt our thread
if ((mythread != null) && mythread.isAlive()) {
mythread.interrupt();
}
monitor.close();
mytimer.stop();
} else {
// otherwise, just
// retrieve the current progress value and...
final int cur = getCurrent();
// ...then update the monitor!
monitor.setProgress(cur);
}
}
/**
* Override this to handle problems differently. Note that this method may or may not be called from the Swing event
* thread. The default implementation just prints to System.err.
*
* @param msg Message about the problem
*/
public void handleProblem(final String msg) {
System.err.println("Transfer problem: " + msg); // NOI18N
}
/**
* Retrieve the value of current, which is the number of bytes transferred so far.
*
* @return number of bytes transfered
*/
public synchronized int getCurrent() {
return current;
}
/**
* DOCUMENT ME!
*
* @param x DOCUMENT ME!
*/
private synchronized void addToCurrent(final int x) {
current += x;
}
/**
* Check whether the task is done yet.
*
* @return DOCUMENT ME!
*/
public synchronized boolean isDone() {
return done;
}
/**
* DOCUMENT ME!
*/
private synchronized void setDone() {
done = true;
setChanged();
notifyObservers("Done"); // NOI18N
}
/**
* Wait for the task to be done. It is probably not a good idea to use this in Swing.
*/
public void waitForDone() {
try {
mythread.join();
} catch (InterruptedException ie) {
}
return;
}
@Override
public final void run() {
try {
final byte[] buf = new byte[BUFSIZ];
int cc;
for (cc = readFrom.read(buf, 0, BUFSIZ); cc > 0; cc = readFrom.read(buf, 0, BUFSIZ)) {
writeTo.write(buf, 0, cc);
addToCurrent(cc); // update the current progress value
// Thread.sleep(200);
if (mythread.isInterrupted()) {
break;
}
setChanged();
notifyObservers(null);
}
} catch (InterruptedIOException ioe) {
handleProblem("Cancelled by user after " // NOI18N
+ current + " bytes."); // NOI18N
} catch (Exception ie) {
handleProblem("IO exception: " + ie); // NOI18N
} finally {
setDone();
if (closeWhenDone) {
if (readFrom != null) {
try {
readFrom.close();
} catch (Exception e2) {
}
}
if (writeTo != null) {
try {
writeTo.close();
} catch (Exception e3) {
}
}
}
}
}
}