net.sf.jcprogress.ProgressThread.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.jcprogress.ProgressThread.java

Source

/*
 * ProgressThread.java
 * 
 * Copyright 2008-2009 Patrick Mairif.
 * The program is distributed under the terms of the Apache License (ALv2).
 * 
 * charset=utf-8, tabstob=4
 */
package net.sf.jcprogress;

import java.util.Date;
import java.util.Locale;
import java.util.ResourceBundle;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * abstract base class for progress indicators
 *
 * @author pmairif
 */
public abstract class ProgressThread extends Thread {
    protected ProgressStatusProvider statusProvider = null;

    protected ResourceBundle resourceBundle = null;

    private ProgressCalculator wholeProgess;

    private Checkpoint checkpoint = null;

    private Checkpoint secondCheckpoint = null;

    private long checkpointSwitchTime = 0;

    //   /**
    //    * elapsed time in milliseconds, when checkpoint was reached
    //    */
    //   private long checkpointElapsedMs = 0;
    //   
    //   /**
    //    * progress count since last checkpoint
    //    */
    //   private int checkpointProgessCount = 0;

    /**
     * time window used to guess the time needed to do the whole job
     */
    private int timeCalcWindowMs = 10000; //10s

    /**
     * milliseconds after which stalled activity is assumed
     */
    private int stalledTimeWindowMs = 500; //0.5s

    /**
     * last update of the indicator
     */
    private long lastIndicatorUpdate;

    /**
     * update interval of the indicator in milli seconds.
     * default is 100ms=0.1s.
     */
    private int indicatorUpdateIntervalMs = 100;

    /**
     * last update of calculated informations
     */
    private long lastInfoUpdate;

    /**
     * update interval of the calculated information in milliseconds
     * default is 200ms=0.2s.
     */
    private int infoUpdateIntervalMs = 200;

    private long guessedEnd = 0;

    private long guessedWholeTime = 0;

    private boolean askedToStop = false;

    /**
     * Logger for this class
     */
    private final Log logger = LogFactory.getLog(ProgressThread.class);

    /**
     * create new progress indicator. 
     * @param statusProvider   ProgressStatusProvider to use
     */
    public ProgressThread(ProgressStatusProvider statusProvider) {
        this(statusProvider, Locale.getDefault());
    }

    /**
     * create new progress indicator. 
     * @param statusProvider   ProgressStatusProvider to use
     * @param locale         preferred locale
     */
    public ProgressThread(ProgressStatusProvider statusProvider, Locale locale) {
        this.statusProvider = statusProvider;

        long now = System.currentTimeMillis(); //memorize current time
        int wholeCount = getWholeCount();

        checkpointSwitchTime = now;
        checkpoint = new Checkpoint(wholeCount, 0, 0, stalledTimeWindowMs, now);
        secondCheckpoint = checkpoint;
        wholeProgess = new ProgressCalculator(now, wholeCount, stalledTimeWindowMs);

        lastIndicatorUpdate = now;
        lastInfoUpdate = now;

        this.resourceBundle = ResourceBundle.getBundle("net.sf.jcprogress.resources.ProgressResources", locale); //$NON-NLS-1$
    }

    /**
     * time window used to guess the time needed to do the whole job
     * @param timeCalcWindowMs the timeCalcWindowMs to set
     */
    public void setTimeCalcWindowMs(int timeCalcWindowMs) {
        this.timeCalcWindowMs = timeCalcWindowMs;
    }

    /**
     * time window used to guess the time needed to do the whole job
     * @return the timeCalcWindowMs
     */
    public int getTimeCalcWindowMs() {
        return this.timeCalcWindowMs;
    }

    /**
     * milliseconds after which stalled activity is assumed
     * @param stalledTimeWindowMs the stalledTimeWindowMs to set
     */
    public void setStalledTimeWindowMs(int stalledTimeWindowMs) {
        this.stalledTimeWindowMs = stalledTimeWindowMs;
    }

    /**
     * milliseconds after which stalled activity is assumed
     * @return the stalledTimeWindowMs
     */
    public int getStalledTimeWindowMs() {
        return this.stalledTimeWindowMs;
    }

    @Override
    public void run() {
        if (!System.getProperty("net.jcprogress.disable", "false").equalsIgnoreCase("true")) {
            try {
                while (!askedToStop) {
                    update(false);
                    sleep(100);
                }

                update(true); //chance to show 100%, if finished
            } catch (InterruptedException e) {
                logger.error("run() - interrupted: " + e.getMessage()); //$NON-NLS-1$
            }

            afterLastInvoking();
        }
    }

    /**
     * update the progress bar.
     * 
     * call this method regularly, if you don't use it as thread.
     */
    public void update() {
        update(false);
    }

    /**
     * update the progress bar.
     * 
     * call this method regularly, if you don't use it as thread.
     * 
     * @param force true, to force updating
     */
    public void update(boolean force) {
        long now = System.currentTimeMillis();

        //update calculated progress information
        if (force || now - lastInfoUpdate > infoUpdateIntervalMs) {
            lastInfoUpdate = now;

            progressCalculations();
        }

        //update indicator
        if (force || now - lastIndicatorUpdate > indicatorUpdateIntervalMs) {
            lastIndicatorUpdate = now;
            show();
        }
    }

    /**
     * show/update progress indicator
     */
    abstract protected void show();

    /**
     * perhaps there is sth. to do after the last invoking (in stop or 100%)
     */
    abstract public void afterLastInvoking();

    public boolean isStalled() {
        return checkpoint.getCalculator().isStalled();
    }

    public boolean hasData() {
        return checkpoint.getCalculator().hasData();
    }

    /**
     * @return Returns the elapsedTime.
     */
    public long getElapsedTime() {
        return System.currentTimeMillis() - wholeProgess.getStartTime();
    }

    /**
     * @return Returns the guessedEnd.
     */
    public Date getGuessedEnd() {
        return new Date(guessedEnd);
    }

    /**
     * @return Returns the guessedWholeTime.
     */
    public long getGuessedWholeTime() {
        return guessedWholeTime;
    }

    /**
     * @return Returns the start.
     */
    public Date getStart() {
        return new Date(wholeProgess.getStartTime());
    }

    /**
     * @return Returns the wholeCount.
     */
    public int getWholeCount() {
        if (statusProvider != null)
            return statusProvider.getWholeProcessCount();

        return 0;
    }

    int getCurrentCount() {
        if (statusProvider != null)
            return statusProvider.getCurrentProgressCount();

        return 0;
    }

    /**
     * ask to stop and return immediately
     */
    public void askToStop() {
        this.askedToStop = true;
    }

    /**
     * ask to stop and wait until stopped.
     */
    public void waitToStop() {
        try {
            askToStop();
            while (isAlive()) {
                sleep(100);
            }
        } catch (InterruptedException e) {
            logger.error("waitToStop() - interrupted exception: " + e.getMessage()); //$NON-NLS-1$
        }
    }

    /**
     * get the update interval of the indicator in milli seconds.
     */
    public int getIndicatorUpdateIntervalMs() {
        return this.indicatorUpdateIntervalMs;
    }

    /**
     * set the update interval of the indicator in milliseconds.
     */
    public void setIndicatorUpdateIntervalMs(int indicatorUpdateIntervalMs) {
        this.indicatorUpdateIntervalMs = indicatorUpdateIntervalMs;
    }

    /**
     * get the update interval of the calculated information in milli seconds
     */
    public int getInfoUpdateIntervalMs() {
        return this.infoUpdateIntervalMs;
    }

    /**
     * set the update interval of the calculated information in milli seconds
     */
    public void setInfoUpdateIntervalMs(int infoUpdateIntervalMs) {
        this.infoUpdateIntervalMs = infoUpdateIntervalMs;
    }

    public float getCurrentPercentage() {
        return (float) wholeProgess.getCurrentPercentage();
    }

    /**
     * progress calculations
     */
    protected void progressCalculations() {
        int wholeCount = getWholeCount();
        int currentCount = getCurrentCount();

        wholeProgess.setProgressCount(currentCount);
        wholeProgess.setProgressWhole(wholeCount);

        checkpoint.setProgressCount(currentCount);
        checkpoint.setProgressWhole(wholeCount);

        secondCheckpoint.setProgressCount(currentCount);
        secondCheckpoint.setProgressWhole(wholeCount);

        guessedEnd = checkpoint.estimateEndTime();
        guessedWholeTime = checkpoint.estimateWholeTime();

        long now = System.currentTimeMillis();
        if (now - checkpointSwitchTime >= timeCalcWindowMs) {
            //use two shifted checkpoints to avoid starting without data on switch
            checkpoint = secondCheckpoint;
            secondCheckpoint = new Checkpoint(wholeCount, currentCount, now - wholeProgess.getStartTime(),
                    stalledTimeWindowMs, now);
            checkpointSwitchTime = now;
        }
    }
}