Package ch.tatool.core.executable

Source Code of ch.tatool.core.executable.BlockingExecutable

/*******************************************************************************
* Copyright (c) 2011 Michael Ruflin, Andr� Locher, Claudia von Bastian.
*
* This file is part of Tatool.
*
* Tatool 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 3 of the License, or
* (at your option) any later version.
*
* Tatool 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 Tatool. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package ch.tatool.core.executable;

import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.tatool.core.element.ElementUtils;
import ch.tatool.core.element.NodeImpl;
import ch.tatool.core.element.handler.KeyEventHandler;
import ch.tatool.element.Executable;
import ch.tatool.exec.ExecutionContext;

/**
* Blocking executable element implementation
*
* This implementation blocks the executable thread until finishExecution is called.
*
* Prior to calling finishExecution, a lock needs to be acquired. This way each thread
* finishing can first check whether it is "the first" or simply abort its operation in
* case it is not.
*
* @author Michael Ruflin
*/
public abstract class BlockingExecutable extends NodeImpl implements Executable, KeyEventDispatcher {
   
    private Logger logger = LoggerFactory.getLogger(BlockingExecutable.class);
   
    /** ExecutionContext provided by the Executor. */
    private ExecutionContext executionContext;
   
    /** Thread that called execute(). */
    private Thread executeCallerThread;
   
    /** Finishing thread.
     *
     * Finish can be called from different place, timeout threads, user input,
     * call to cancel etc. This variable holds a reference to the thread that
     * was granted finishing rights.
     */
    private Thread finishingThread;
   
    /** Boolean that signals whether stop has been called already. */
    private boolean running = false;
   
    public BlockingExecutable() {
      super();
    }
   
    public BlockingExecutable(String defaultId) {
        super(defaultId);
    }
   
    public ExecutionContext getExecutionContext() {
      return executionContext;
    }
   
    public void setExecutionContext(ExecutionContext executionContext) {
      this.executionContext = executionContext;
    }
   
    /**
     * Implementation of execute.
     *
     * Will call startExecution on the awt thread and then
     * block the caller thread until finishExecution is called
     */
    public final void execute() {
        // initialize
      synchronized(this) {
        running = true;
        executeCallerThread = Thread.currentThread();
        finishingThread = null;
        // add keyboard listener
          KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
      }

        // start execution
      startExecution();
       
        // put current thread to sleep until we wake it up with notify()
        // only wait as long as we don't have a request for finishing an outcome
        while (finishingThread == null) {
            try {
                synchronized(executeCallerThread) {
                    executeCallerThread.wait();
                }
            } catch(InterruptedException e) {
                logger.warn("TaskOutcome thread interrupted", e);
                e.printStackTrace();
            }
        }
       
        // cleanup
        synchronized(this) {
          // remove keyboard listener
          KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
          executeCallerThread = null;
          running = false;
        }
    }
   
    /**
     * Start actual execution.
     */
    protected abstract void startExecution();
   
    /**
     * Request the lock to finish execution.
     *
     * This method needs to be called prior to calling finishExecution.
     * Calling finishExecution is only allowed for the thread that
     * receives true as a result.
     */
    protected synchronized boolean getFinishExecutionLock() {
      if (running && finishingThread == null) {
        finishingThread = Thread.currentThread();
        return true;
      } else {
        return false;
      }
    }
   
    /**
     * Call this method to finish execution.
     *
     * Note that you need to request a lock from getFInishExecutionLock before calling this method.
     * This method will release the Executors thread, so finish any work *before* calling this method.
     */
    protected void finishExecution() {
      // concurrency check
      if (finishingThread == null) {
        throw new IllegalStateException("You need first to fetch true from getFinishExecutionLock() before calling this method.");
      } else if (finishingThread != Thread.currentThread()) {
        throw new IllegalStateException("Another thread was attributed with the finishExecutionLock!.");
      }
     
      // wake up the element execution thread, but first set the outcome
    synchronized(executeCallerThread) {
      executeCallerThread.notifyAll();
    }
  }
   
    /**
     * Cancels the task.
     *
     * This method fetches the finish execution lock and if successful calls cancelExecution.
     * Once cancelExecution returns finishExecution is called
     */
    public void cancel() {
      boolean first = getFinishExecutionLock();
      if (first) {
        cancelExecution();
        finishExecution();
      }
    }
   
    /** Called when cancel successfully acquires the finish execution lock. */
    protected void cancelExecution() {
    }
   
    public boolean dispatchKeyEvent(KeyEvent e) {
    if (e.getID() == KeyEvent.KEY_PRESSED) {
      if (getExecutionContext() != null) {
        KeyEventHandler keyEventHandler = (KeyEventHandler) ElementUtils.findHandlerInStackByType(getExecutionContext(), KeyEventHandler.class);
        if (keyEventHandler != null) {
          keyEventHandler.triggerKeyEvent(e.getKeyCode(), getExecutionContext());
        }
      }
    }
    // never consume the event...
    return false;
  }
}
TOP

Related Classes of ch.tatool.core.executable.BlockingExecutable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.