All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.pdfview.BaseWatchable Maven / Gradle / Ivy

The newest version!
/*
 * $Id: BaseWatchable.java,v 1.5 2009-02-09 17:14:32 tomoke Exp $
 *
 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.sun.pdfview;

/**
 * An abstract implementation of the watchable interface, that is extended
 * by the parser and renderer to do their thing.
 */
public abstract class BaseWatchable implements Watchable, Runnable {

    /** the current status, from the list in Watchable */
    private int status = Watchable.UNKNOWN;
    /** a lock for status-related operations */
    private Object statusLock = new Object();
    /** a lock for parsing operations */
    private Object parserLock = new Object();
    /** when to stop */
    private Gate gate;
    /** suppress local stack trace on setError. */
    private static boolean SuppressSetErrorStackTrace = false;
    /** the thread we are running in */
    private Thread thread;

    /** 
     * Creates a new instance of BaseWatchable
     */
    protected BaseWatchable() {
        setStatus(Watchable.NOT_STARTED);
    }

    /**
     * Perform a single iteration of this watchable.  This is the minimum
     * granularity which the go() commands operate over.
     *
     * @return one of three values: 
    *
  • Watchable.RUNNING if there is still data to be processed *
  • Watchable.NEEDS_DATA if there is no data to be processed but * the execution is not yet complete *
  • Watchable.COMPLETED if the execution is complete *
*/ protected abstract int iterate() throws Exception; /** * Prepare for a set of iterations. Called before the first iterate() call * in a sequence. Subclasses should extend this method if they need to do * anything to setup. */ protected void setup() { // do nothing } /** * Clean up after a set of iterations. Called after iteration has stopped * due to completion, manual stopping, or error. */ protected void cleanup() { // do nothing } public void run() { // System.out.println(Thread.currentThread().getName() + " starting"); // call setup once we started if (getStatus() == Watchable.NOT_STARTED) { setup(); } setStatus(Watchable.PAUSED); synchronized (parserLock) { while (!isFinished() && getStatus() != Watchable.STOPPED) { if (isExecutable()) { // set the status to running setStatus(Watchable.RUNNING); try { // keep going until the status is no longer running, // our gate tells us to stop, or no-one is watching while ((getStatus() == Watchable.RUNNING) && (gate == null || !gate.iterate())) { // update the status based on this iteration setStatus(iterate()); } // make sure we are paused if (getStatus() == Watchable.RUNNING) { setStatus(Watchable.PAUSED); } } catch (Exception ex) { setError(ex); } } else { // System.out.println(getName() + " waiting: status = " + getStatusString()); // wait for our status to change synchronized (statusLock) { if (!isExecutable()) { try { statusLock.wait(); } catch (InterruptedException ie) { // ignore } } } } } } // System.out.println(Thread.currentThread().getName() + " exiting: status = " + getStatusString()); // call cleanup when we are done if (getStatus() == Watchable.COMPLETED || getStatus() == Watchable.ERROR) { cleanup(); } // notify that we are no longer running thread = null; } /** * Get the status of this watchable * * @return one of the well-known statuses */ public int getStatus() { return status; } /** * Return whether this watchable has finished. A watchable is finished * when its status is either COMPLETED, STOPPED or ERROR */ public boolean isFinished() { int s = getStatus(); return (s == Watchable.COMPLETED || s == Watchable.ERROR); } /** * return true if this watchable is ready to be executed */ public boolean isExecutable() { return ((status == Watchable.PAUSED || status == Watchable.RUNNING) && (gate == null || !gate.stop())); } /** * Stop this watchable. Stop will cause all processing to cease, * and the watchable to be destroyed. */ public void stop() { setStatus(Watchable.STOPPED); } /** * Start this watchable and run in a new thread until it is finished or * stopped. * Note the watchable may be stopped if go() with a * different time is called during execution. */ public synchronized void go() { gate = null; execute(false); } /** * Start this watchable and run until it is finished or stopped. * Note the watchable may be stopped if go() with a * different time is called during execution. * * @param synchronous if true, run in this thread */ public synchronized void go(boolean synchronous) { gate = null; execute(synchronous); } /** * Start this watchable and run for the given number of steps or until * finished or stopped. * * @param steps the number of steps to run for */ public synchronized void go(int steps) { gate = new Gate(); gate.setStopIterations(steps); execute(false); } /** * Start this watchable and run for the given amount of time, or until * finished or stopped. * * @param millis the number of milliseconds to run for */ public synchronized void go(long millis) { gate = new Gate(); gate.setStopTime(millis); execute(false); } /** * Wait for this watchable to finish */ public void waitForFinish() { synchronized (statusLock) { while (!isFinished() && getStatus() != Watchable.STOPPED) { try { statusLock.wait(); } catch (InterruptedException ex) { // ignore } } } } /** * Start executing this watchable * * @param synchronous if true, run in this thread */ protected synchronized void execute(boolean synchronous) { // see if we're already running if (thread != null) { // we're already running. Make sure we wake up on any change. synchronized (statusLock) { statusLock.notifyAll(); } return; } else if (isFinished()) { // we're all finished return; } // we'return not running. Start up if (synchronous) { thread = Thread.currentThread(); run(); } else { thread = new Thread(this); thread.setName(getClass().getName()); thread.start(); } } /** * Set the status of this watchable */ protected void setStatus(int status) { synchronized (statusLock) { this.status = status; // System.out.println(getName() + " status set to " + getStatusString()); statusLock.notifyAll(); } } /** * return true if we would be suppressing setError stack traces. * * @return boolean */ public static boolean isSuppressSetErrorStackTrace () { return SuppressSetErrorStackTrace; } /** * set suppression of stack traces from setError. * * @param suppressTrace */ public static void setSuppressSetErrorStackTrace(boolean suppressTrace) { SuppressSetErrorStackTrace = suppressTrace; } /** * Set an error on this watchable */ protected void setError(Exception error) { if (!SuppressSetErrorStackTrace) { error.printStackTrace(); } setStatus(Watchable.ERROR); } private String getStatusString() { switch (getStatus()) { case Watchable.NOT_STARTED: return "Not started"; case Watchable.RUNNING: return "Running"; case Watchable.NEEDS_DATA: return "Needs Data"; case Watchable.PAUSED: return "Paused"; case Watchable.STOPPED: return "Stopped"; case Watchable.COMPLETED: return "Completed"; case Watchable.ERROR: return "Error"; default: return "Unknown"; } } /** A class that lets us give it a target time or number of steps, * and will tell us to stop after that much time or that many steps */ class Gate { /** whether this is a time-based (true) or step-based (false) gate */ private boolean timeBased; /** the next gate, whether time or iterations */ private long nextGate; /** set the stop time */ public void setStopTime(long millisFromNow) { timeBased = true; nextGate = System.currentTimeMillis() + millisFromNow; } /** set the number of iterations until we stop */ public void setStopIterations(int iterations) { timeBased = false; nextGate = iterations; } /** check whether we should stop. */ public boolean stop() { if (timeBased) { return (System.currentTimeMillis() >= nextGate); } else { return (nextGate < 0); } } /** Notify the gate of one iteration. Returns true if we should * stop or false if not */ public boolean iterate() { if (!timeBased) { nextGate--; } return stop(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy