/* * This file is part of Alida, a Java library for * Advanced Library for Integrated Development of Data Analysis Applications. * * Copyright (C) 2010 - @YEAR@ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Fore more information on Alida, visit * * http://www.informatik.uni-halle.de/alida/ * */ package de.unihalle.informatik.Alida.operator; import javax.swing.event.EventListenerList; import de.unihalle.informatik.Alida.exceptions.ALDOperatorException; import de.unihalle.informatik.Alida.operator.events.*; /** * Operator class with inherent event handling for execution control. * <p> * This operator acts as listener for `Alida` control events. On receiving * events the operator changes its control status which may be used to * control operator execution, and in particular to interrupt calculations * in a controlled fashion, i.e. to keep results already obtained. * * @author moeller */ public abstract class ALDOperatorControllable extends ALDOperator implements ALDControlEventListener, ALDControlEventReporter, ALDConfigurationEventListener, ALDConfigurationEventReporter { /** * Commands for controlling the operator. * <p> * The status is supposed to be switched externally and the operator * is expected to react on changes as soon as possible. */ public static enum OperatorControlStatus { /** * Default state after instantiation. */ OP_INIT, /** * Run the operator. */ OP_RUN, /** * Stop the operator as soon as possible, save data if possible. */ OP_STOP, /** * Pause the operator. */ OP_PAUSE, /** * Resume operator after pause. */ OP_RESUME, /** * Do one step. */ OP_STEP, /** * Stop immediately, even in case of data loss. */ OP_KILL } /** * Actual operator status. */ public static enum OperatorExecutionStatus { /** * Default state after instantiation. */ OP_EXEC_INIT, /** * Operator is running. */ OP_EXEC_RUNNING, /** * Operator terminated or was killed. */ OP_EXEC_TERMINATED, /** * Operator is paused. */ OP_EXEC_PAUSED } /** * Flag for step-wise execution. */ protected boolean stepWiseExecution = false; /** * Step size in step-wise execution mode. */ protected int stepSize = 1; /** * Flag for recursive propagation of events to nested listeners. */ protected boolean notifyListenersRecursively = false; /** * List of control event listeners attached to this reporter. */ protected volatile EventListenerList controlEventlistenerList = new EventListenerList(); /** * List of configuration event listeners attached to this reporter. */ protected volatile EventListenerList configurationEventlistenerList = new EventListenerList(); /** * Control status of operator, used to stop/pause/resume calculations. */ protected volatile OperatorControlStatus operatorStatus = OperatorControlStatus.OP_INIT; /** * Actual execution state of operator. */ protected volatile OperatorExecutionStatus operatorExecStatus = OperatorExecutionStatus.OP_EXEC_INIT; /** * Default constructor. * @throws ALDOperatorException */ public ALDOperatorControllable() throws ALDOperatorException { super(); } /** * Specify if events are to be passed forward to nested listeners or not. */ public void setNotifyRecursiveFlag(boolean flag) { this.notifyListenersRecursively = flag; } /** * Get the current execution status of the operator. * @return Current execution status. */ public OperatorExecutionStatus getExecutionStatus() { return this.operatorExecStatus; } /** * Function for indicating if step-wise execution is supported. * @return If true, operator may be executed step-wise. */ public abstract boolean supportsStepWiseExecution(); @Override public void handleALDControlEvent(ALDControlEvent event) { switch(event.getEventType()) { case RUN_EVENT: this.operatorStatus = OperatorControlStatus.OP_RUN; break; case PAUSE_EVENT: this.operatorStatus = OperatorControlStatus.OP_PAUSE; break; case STOP_EVENT: this.operatorStatus = OperatorControlStatus.OP_STOP; break; case STEP_EVENT: this.operatorStatus = OperatorControlStatus.OP_STEP; break; case KILL_EVENT: // kills the thread immediately Thread.currentThread().interrupt(); break; case RESUME_EVENT: this.operatorStatus = OperatorControlStatus.OP_RESUME; break; } // send event to all sub-operators and their listeners if (this.notifyListenersRecursively) this.fireALDControlEvent(new ALDControlEvent(this,event.getEventType())); } /* * Implementation of event functions below according to * * {@link http://www.exampledepot.com/egs/java.util/custevent.html} */ @Override public void addALDControlEventListener(ALDControlEventListener listener) { this.controlEventlistenerList.add(ALDControlEventListener.class, listener); } @Override public void removeALDControlEventListener(ALDControlEventListener listener) { this.controlEventlistenerList.remove(ALDControlEventListener.class, listener); } @Override public void fireALDControlEvent(ALDControlEvent event) { // Guaranteed to return a non-null array Object[] listeners = this.controlEventlistenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==ALDControlEventListener.class) { // Lazily create the event: ((ALDControlEventListener)listeners[i+1]).handleALDControlEvent( new ALDControlEvent(this, event.getEventType())); } } } @Override public void addALDConfigurationEventListener( ALDConfigurationEventListener listener) { this.configurationEventlistenerList.add(ALDConfigurationEventListener.class, listener); } @Override public void removeALDConfigurationEventListener( ALDConfigurationEventListener listener) { this.configurationEventlistenerList.remove( ALDConfigurationEventListener.class, listener); } @Override public void fireALDConfigurationEvent(ALDConfigurationEvent event) { // Guaranteed to return a non-null array Object[] listeners = this.configurationEventlistenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==ALDConfigurationEventListener.class) { // Lazily create the event: ((ALDConfigurationEventListener)listeners[i+1]). handleALDConfigurationEvent(event); // new ALDConfigurationEvent(this, event.getEventMessage())); } } } @Override public void handleALDConfigurationEvent(ALDConfigurationEvent event) { this.stepSize = event.getStepSize(); if (event.doStepwiseExecution()) this.stepWiseExecution = true; else this.stepWiseExecution = false; // send event to all sub-operators, with sending object updated if (this.notifyListenersRecursively) this.fireALDConfigurationEvent(event); // new ALDConfigurationEvent(this,event.getEventMessage())); } }