/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: AbstractExecutionObject.java 2576 2007-11-02 16:00:34Z drmlipp $
*
* $Log$
* Revision 1.13 2007/09/21 07:57:12 drmlipp
* Removed superfluous import.
*
* Revision 1.12 2007/09/21 06:19:35 mlipp
* Fixed problem with NamingException during process deletion.
*
* Revision 1.11 2007/05/03 21:58:19 mlipp
* Internal refactoring for making better use of local EJBs.
*
*/
package de.danet.an.workflow.domain;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import de.danet.an.workflow.api.ProcessDefinition;
import de.danet.an.workflow.api.Activity.ClosedCompletedState;
import de.danet.an.workflow.apix.ExtActivity;
import de.danet.an.workflow.apix.ExtProcess;
import de.danet.an.workflow.internalapi.ExtExecutionObjectLocal;
import de.danet.an.workflow.localcoreapi.WfExecutionObjectLocal;
import de.danet.an.workflow.omgcore.AlreadySuspendedException;
import de.danet.an.workflow.omgcore.CannotResumeException;
import de.danet.an.workflow.omgcore.CannotStopException;
import de.danet.an.workflow.omgcore.CannotSuspendException;
import de.danet.an.workflow.omgcore.HistoryNotAvailableException;
import de.danet.an.workflow.omgcore.InvalidControlOperationException;
import de.danet.an.workflow.omgcore.InvalidDataException;
import de.danet.an.workflow.omgcore.InvalidPriorityException;
import de.danet.an.workflow.omgcore.InvalidStateException;
import de.danet.an.workflow.omgcore.NotRunningException;
import de.danet.an.workflow.omgcore.NotSuspendedException;
import de.danet.an.workflow.omgcore.ProcessData;
import de.danet.an.workflow.omgcore.ResultNotAvailableException;
import de.danet.an.workflow.omgcore.SourceNotAvailableException;
import de.danet.an.workflow.omgcore.TransitionNotAllowedException;
import de.danet.an.workflow.omgcore.UpdateNotAllowedException;
import de.danet.an.workflow.omgcore.WfAuditEvent;
import de.danet.an.workflow.omgcore.WfExecutionObject;
import de.danet.an.workflow.omgcore.WfStateAuditEvent;
import de.danet.an.workflow.omgcore.WfExecutionObject.ClosedState;
import de.danet.an.workflow.omgcore.WfExecutionObject.NotRunningState;
import de.danet.an.workflow.omgcore.WfExecutionObject.OpenState;
import de.danet.an.workflow.omgcore.WfExecutionObject.State;
/**
* <code>AbstractExecutionObject</code> represents a base
* implementation of the interface {@link
* de.danet.an.workflow.api.ExecutionObject
* <code>ExecutionObject</code>}.<P>
*
* With logger level <code>DEBUG</code>, event handling information
* will be logged.
*/
public abstract class AbstractExecutionObject
implements WfExecutionObjectLocal, ExtExecutionObjectLocal {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog
(AbstractExecutionObject.class);
// Make sure that loading this class loads the new states
static {
State s = RunningState.RUNNING;
s = DebugState.ABORTING;
s = SuspendedState.SUSPENDED;
s = ClosedCompletedState.NORMAL;
}
//
// Persistent attribute accessors and associated methods
//
/**
* The getter method for the persistent attribute <code>key</code>.
*
* @return the value of key.
*/
protected abstract String getPaKey();
/**
* The getter method for the persistent attribute <code>name</code>.
*
* @return the value of name.
* @see #setPaName
*/
protected abstract String getPaName();
/**
* The setter method for the persistent attribute <code>name</code>.
*
* @param newName the new value of name.
* @see #getPaName
*/
protected abstract void setPaName(String newName);
/**
* The getter method for the persistent attribute <code>description</code>.
*
* @return the value of description.
* @see #setPaDescription
*/
protected abstract String getPaDescription();
/**
* The setter method for the persistent attribute <code>description</code>.
*
* @param newDescription the new value of description.
* @see #getPaDescription
*/
protected abstract void setPaDescription(String newDescription);
/**
* The getter method for the persistent attribute <code>priority</code>.
*
* @return the value of priority.
* @see #setPaPriority
*/
protected abstract Priority getPaPriority();
/**
* The setter method for the persistent attribute <code>priority</code>.
*
* @param newPriority the new value of priority.
* @see #getPaPriority
*/
protected abstract void setPaPriority(Priority newPriority);
/**
* The getter method for the persistent attribute
* <code>lastStateTime</code>. This attribute holds the time when
* the state was last changed. This may happen from an explicit
* action like the <code>complete()</code> method or via a state
* change propagation from another WfmExecutionObject.
*
* @return the value of lastStateTime.
* @see #setPaLastStateTime
*/
protected abstract Date getPaLastStateTime();
/**
* The setter method for the persistent attribute
* <code>lastStateTime</code>.
*
* @param newLastStateTime the new value of lastStateTime.
* @see #getPaLastStateTime
*/
protected abstract void setPaLastStateTime(Date newLastStateTime);
/**
* The getter method for the persistent attribute
* <code>typedState</code>.
*
* @return the value of typedState.
* @see #setPaTypedState
*/
protected abstract State getPaTypedState();
/**
* The setter method for the persistent attribute
* <code>typedState</code>.
*
* @param newTypedState the new value of typedState.
* @see #getPaTypedState
*/
protected abstract void setPaTypedState(State newTypedState);
/**
* The getter method for the persistent attribute <code>debug</code>.
*
* @return the value of debug.
* @see #setPaDebug
*/
protected abstract boolean getPaDebug();
/**
* The setter method for the persistent attribute <code>debug</code>.
*
* @param newDebug the new value of debug.
* @see #getPaDebug
*/
protected abstract void setPaDebug(boolean newDebug);
/**
* The getter method for the persistent attribute
* <code>auditEventSelection</code>.
*
* @return the value of auditEventSelection.
* @see #setPaAuditEventSelection
*/
protected abstract int getPaAuditEventSelection();
/**
* The setter method for the persistent attribute
* <code>auditEventSelection</code>.
*
* @param newAuditEventSelection the new value of
* auditEventSelection.
* @see #getPaAuditEventSelection
*/
protected abstract void
setPaAuditEventSelection (int newAuditEventSelection);
/**
* The getter method for the persistent attribute
* <code>storeAuditEvents</code>.
*
* @return the value of storeAuditEvents.
* @see #setPaStoreAuditEvents
*/
protected abstract boolean getPaStoreAuditEvents();
/**
* The setter method for the persistent attribute
* <code>storeAuditEvents</code>.
*
* @param newStoreAuditEvents the new value of storeAuditEvents.
* @see #getPaStoreAuditEvents
*/
protected abstract void setPaStoreAuditEvents(boolean newStoreAuditEvents);
/**
* Initializes the class, i.e. resets all attributes to default
* values. Note that
* {@link #refresh <code>refresh</code>} will be called subsequently.
*
* @see #dispose
*/
protected void init () {
setPaLastStateTime (new Date());
setPaPriority (Priority.NORMAL);
setPaDebug (false);
}
/**
* Called after change of persistent attributes. May be used to
* synchronise state derived from persistent attributes with
* the new values.
*
* @see #init
*/
protected void refresh () {
}
/**
* Releases all allocated resources. The object will be in an
* unusable state until resources are reallocated by calling
* {@link #init <code>init</code>} and
* {@link #refresh <code>refresh</code>}.
*/
protected void dispose () {
}
//
// Domain methods
//
/**
* Returns a hash code value for this object.<P>
*
* Note that stubs do not in general implement
* <code>hashCode</code> correctly, so even if two execution
* objects are equal (<code>this.equals(obj)</code> is
* <code>true</code>) <code>this.hashCode()</code> need not be
* equal to <code>obj.hashCode()</code>.
*
* @return the hash code value.
*/
public int hashCode () {
try {
return getPaKey().hashCode();
} catch (NullPointerException e) {
// workaround for jboss bug #634362
return 1;
}
}
/**
* Returns the name of the execution object.
* @return name of the execution object
*/
public String name () {
return getPaName();
}
/**
* Set a new name of the execution object.
* @param newValue new name.
* @see #name
*/
public void setName (String newValue) {
setPaName (newValue);
}
/**
* Returns the key of the execution object.
* @return key of the execution object
*/
public String key () {
return getPaKey();
}
/**
* Returns the description of the execution object.
* @return description of the execution object
*/
public String description () {
return getPaDescription();
}
/**
* Set a new description of the execution object.
* @param newValue new description
* @see #description
*/
public void setDescription (String newValue) {
setPaDescription (newValue);
}
/**
* Updates process context of the execution object.
* @param newValues the name-value pairs to be set.
* @throws InvalidDataException If a name or value type does not match
* the signature of this process.
* @throws UpdateNotAllowedException If the update is not allowed.
*/
public void setProcessContext (ProcessData newValues) throws
InvalidDataException, UpdateNotAllowedException {
throw new UpdateNotAllowedException("Not implemented.");
}
/**
* Returns the priority of the execution object.
* @return priority of the execution object
*/
public int priority () {
return getPaPriority().toInt();
}
/**
* For the first iteration throws an
* <code>UpdateNotAllowedException</code>.
* @param newValue new priority
* @throws InvalidPriorityException when the specified priority is out of
* range.
* @throws UpdateNotAllowedException when the priority cannot be updated.
*/
public void setPriority (int newValue)
throws InvalidPriorityException, UpdateNotAllowedException {
setPaPriority (Priority.fromInt (newValue));
}
/**
* Enable or disable debugging of the execution object.
* @param debug if the execution object is to be debugged
* @throws InvalidStateException if changing debug mode is not
* allowed
*/
public void setDebugEnabled (boolean debug) throws InvalidStateException {
setPaDebug (debug);
}
/**
* Checks if the execution object is in debugging mode.
*
* @return <code>true</code> if the execution object is in
* debugging mode
*/
public boolean debugEnabled () {
return getPaDebug ();
}
//
// state handling
//
/**
* Returns the last state time of the execution object.
* @return last state time of the execution object
*/
public Date lastStateTime () {
return getPaLastStateTime();
}
/**
* Returns a list of all the valid states (as <code>State</code> objects)
* that can be reached
* from the current state. If there is no valid state, the collection
* will be empty.
* @return list of all the valid states
*/
protected Collection validTypedStates () {
Collection c = (Collection)getStateTransitionMap()
.get(getPaTypedState());
if (c == null) {
return new ArrayList(0);
}
return c;
}
/**
* Returns a list of all the valid states as strings that can be reached
* from the current state. If there is no valid state, the collection
* will be empty.
* @return list of all the valid states
*/
public Collection validStates () {
Collection c = (Collection)getStateTransitionMap()
.get(getPaTypedState());
if (c == null) {
return new ArrayList(0);
}
Collection cs = new ArrayList();
for (Iterator i = c.iterator(); i.hasNext();) {
cs.add(((State)i.next()).toString());
}
return cs;
}
/**
* Returns the {@link java.util.Map <code>Map</code>} that maps
* the execution object states to a {@link java.util.Map
* <code>List</code>} of reachable process states. <P>
*
* The map returns the state transitions allowed as parameters of
* {@link
* de.danet.an.workflow.localcoreapi.WfExecutionObjectLocal#changeState
* <code>changeState</code>} only. I.e. the map does not reflect
* all possible transitions, there may be more, but those are only
* accessible to the workflow engine itself.
* @return the resulting map.
*/
protected abstract Map getStateTransitionMap ();
/**
* Updates the current state of the execution object. As a result
* the state of execution objects associated with this execution
* object might be updated, too. This implementation effectively
* calls {@link ExecutionObjectLocal#changeState
* <code>changeState(State)</code>} after converting the argument
* to <code>State</code>. Derived classes therefore only need to
* override <code>changeState(State)</code>.
*
* @param newState State to change to.
* @throws InvalidStateException If <code>newState</code> is an invalid
* state for the execution object.
* @throws TransitionNotAllowedException If the transition from the current
* state to <code>newState</code> is not allowed.
*/
public void changeState (String newState)
throws InvalidStateException, TransitionNotAllowedException {
changeState (State.fromString (newState));
}
/**
* Returns the internal state, i.e. the state represented as
* <code>State</code> object.
* @return internal state.
* @see #updateState
*/
public State typedState () {
return getPaTypedState();
}
/**
* Updates the current state of the execution object. As a result
* the state of execution objects associated with this execution object
* may be updated, too. This method uses
* the <code>State</code> class to represent states.
*
* @param newState the new state.
* @throws InvalidStateException If <code>newState</code> is an invalid
* state for the execution object.
* @throws TransitionNotAllowedException If the transition from the current
* state to <code>newState</code> is not allowed.
*/
public void changeState (State newState)
throws InvalidStateException,
TransitionNotAllowedException {
try {
if (newState.isSameOrSubState(NotRunningState.SUSPENDED)) {
suspend ();
return;
}
if (newState == OpenState.RUNNING) {
resume ();
return;
}
if (newState == ClosedState.TERMINATED) {
terminate ();
return;
}
if (newState == ClosedState.ABORTED) {
abort ();
return;
}
} catch (NotRunningException e) {
throw new TransitionNotAllowedException
(e.getClass().getName() + ": " + e.getMessage());
} catch (InvalidControlOperationException e) {
throw new TransitionNotAllowedException
(e.getClass().getName() + ": " + e.getMessage());
}
throw new TransitionNotAllowedException
(toString() + " from " + state() + " to " + newState.toString());
}
/**
* Sets the state of this object. The method updates the last
* state time and fires a state change event.
*
* @param newState new state.
* @see #typedState
*/
protected void updateState(State newState) {
State oldState = getPaTypedState();
setPaLastStateTime (new Date());
setPaTypedState (newState);
int auditSel = getPaAuditEventSelection();
// base event information
WfAuditEvent event = auditEventBase
((this instanceof AbstractProcess)
? WfAuditEvent.PROCESS_STATE_CHANGED
: WfAuditEvent.ACTIVITY_STATE_CHANGED);
// Now add general or specific information to the event. Note that we
// must always fire a state audit event if a process closes (see below),
// but we have to add result information only if the event is to be
// published.
if ((this instanceof AbstractProcess)
&& newState.isSameOrSubState(State.CLOSED)
&& (auditSel == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS
|| auditSel == ProcessDefinition
.AUDIT_SELECTION_STATE_EVENTS_ONLY
|| auditSel == ProcessDefinition
.AUDIT_SELECTION_PROCESS_CLOSED_EVENTS_ONLY)) {
try {
event = new DefaultProcessClosedAuditEvent
(event, oldState.toString(), newState.toString(),
((AbstractProcess)this).result());
} catch (ResultNotAvailableException e) {
// Cannot happen, see implementation
logger.debug ("Unexpected exception: " + e.getMessage(), e);
}
} else {
event = new DefaultStateAuditEvent
(event, oldState.toString(), newState.toString());
}
// Note that process closed events
// (case AUDIT_SELECTION_PROCESS_CLOSED_EVENTS_ONLY) are fired
// because they are handled by the process
if (auditSel == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS
|| auditSel==ProcessDefinition.AUDIT_SELECTION_STATE_EVENTS_ONLY
|| AbstractActivity.isHandled(event)
|| AbstractProcess.isHandled(event)) {
fireAuditEvent (event);
}
}
/**
* Like {@link #updateState <code>updateState</code>} this method
* sets the state of this object and fires a state change
* event. The state change event will, however, not be fed back to
* the engine, i.e. it will not lead to follow up activities and
* the last state time will not be updated.<P>
*
* The method is intended to be used for an interim state change,
* i.e. the caller knows that the state will change again before
* the transaction is completed.
*
* @param newState new state.
* @see #typedState
*/
protected void updateInterim(State newState) {
doUpdateNoFeedback(newState, false);
}
/**
* Like {@link #updateState <code>updateState</code>} this method
* sets the state of this object and fires a state change
* event. The state change event will, however, not be fed back to
* the engine, i.e. it will not lead to follow up activities.<P>
*
* The method is intended to be used in cases where the engine triggers
* a state change itself and also performs all actions that are usually
* done in the event handling method.
*
* @param newState new state.
* @see #typedState
*/
protected void updateImmediate(State newState) {
doUpdateNoFeedback(newState, true);
}
private void doUpdateNoFeedback (State newState, boolean updateStateTime) {
State oldState = getPaTypedState();
setPaTypedState (newState);
if (updateStateTime) {
setPaLastStateTime (new Date());
}
int auditSel = getPaAuditEventSelection();
if (auditSel == ProcessDefinition.AUDIT_SELECTION_ALL_EVENTS
|| auditSel==ProcessDefinition.AUDIT_SELECTION_STATE_EVENTS_ONLY) {
fireAuditEvent
(new DefaultStateAuditEvent
(auditEventBase
((this instanceof AbstractProcess)
? WfAuditEvent.PROCESS_STATE_CHANGED
: WfAuditEvent.ACTIVITY_STATE_CHANGED),
oldState.toString(), newState.toString(), true));
}
}
/**
* Returns the workflow state.
* @return the workflow state.
*/
public State workflowState () {
return getPaTypedState().workflowState();
}
/**
* Returns the workflow substate for open execution objects.
* @return the workflow substate.
*/
public State whileOpen () {
return getPaTypedState().whileOpenState();
}
/**
* Returns the workflow substate for open, not running
* execution objects.
* @return the workflow substate.
*/
public State whyNotRunning () {
return getPaTypedState().whyNotRunningState();
}
/**
* Returns the workflow substate for closed
* execution objects.
* @return the workflow substate.
*/
public State howClosed () {
return getPaTypedState().howClosedState();
}
/**
* Returns the string representation of the state.
* @return string representation of the state.
*/
public String state () {
return getPaTypedState().toString();
}
/* Comment copied from Interface. */
public void suspend () throws CannotSuspendException, NotRunningException,
AlreadySuspendedException {
if (typedState().isSameOrSubState(NotRunningState.SUSPENDED)) {
throw new AlreadySuspendedException (toString());
}
if (!typedState().isSameOrSubState(OpenState.RUNNING)) {
throw new NotRunningException (toString() + " is " + state());
}
if (!validTypedStates().contains (NotRunningState.SUSPENDED)) {
throw new CannotSuspendException(toString() + " is " + state());
}
updateState (SuspendedState.SUSPENDED);
}
/* Comment copied from Interface. */
public void resume ()
throws CannotResumeException, NotRunningException,
NotSuspendedException {
if (!typedState().isSameOrSubState(OpenState.RUNNING)
&& !typedState().isSameOrSubState(SuspendedState.SUSPENDED)) {
throw new NotRunningException (toString() + " is " + state());
}
if (!typedState().isSameOrSubState(NotRunningState.SUSPENDED)) {
throw new NotSuspendedException (toString());
}
if (!validTypedStates().contains (OpenState.RUNNING)) {
throw new CannotResumeException(toString() + " is " + state());
}
updateState (RunningState.RUNNING);
}
/* Comment copied from Interface. */
public void terminate () throws CannotStopException, NotRunningException {
throw new CannotStopException(toString() + " cannot be terminated.");
}
/* Comment copied from Interface. */
public void abort () throws CannotStopException, NotRunningException {
throw new CannotStopException(toString() + " cannot be aborted.");
}
/* Comment copied from Interface. */
public abstract Collection history ()
throws HistoryNotAvailableException;
//
// Audit handling
//
/**
* Returns a <code>WfAuditEvent</code> containing information about the
* execution object.
* @param eventType event type
* @return the event containing the required information.
*/
protected abstract WfAuditEvent auditEventBase (String eventType);
private static ThreadLocal queuingEvents
= new ThreadLocal() {
protected Object initialValue() {
return Boolean.FALSE;
}
};
private static ThreadLocal eventQueue
= new ThreadLocal() {
protected Object initialValue() {
return new ArrayList();
}
};
/**
* Process newly generated event. This fall-back implementation
* logs the event with level <code>DEBUG</code> and calls handlers
* for state change events. If the event source is an
* <code>AbstractProcess</code> its <code>handleAuditEvent</code>
* is called. If the event source is an
* <code>AbstractActivity</code> both the activity's and the
* process' handler are called.<P>
*
* This implementation is mainly intended for unit tests on the
* domain level. It must be overridden by the derived classes.
*
* @param event Event
*/
protected void fireAuditEvent(WfAuditEvent event) {
logger.debug (event.toString());
List eq = (List)eventQueue.get();
eq.add (event);
if (((Boolean)queuingEvents.get()).booleanValue()) {
return;
}
queuingEvents.set(Boolean.TRUE);
while (eq.size() > 0) {
event = (WfAuditEvent)eq.remove(0);
if ((event instanceof WfStateAuditEvent)
|| (event instanceof ImplCompleteAuditEvent)) {
try {
WfExecutionObject eo = event.source();
if (eo instanceof ExtProcess) {
((ExtProcess)eo).handleAuditEvent (event);
} else if (eo instanceof ExtActivity) {
ExtActivity aAct = (ExtActivity)eo;
aAct.handleAuditEvent (event);
if (!(event instanceof ImplCompleteAuditEvent)) {
((ExtProcess)aAct
.container()).handleAuditEvent (event);
}
}
} catch (SourceNotAvailableException e) {
// can't do anything about this
logger.error ("Event discarded: " + e.getMessage(), e);
} catch (RemoteException e) {
// shouldn't really happen on domain level
logger.error (e.getMessage(), e);
}
}
}
queuingEvents.set(Boolean.FALSE);
}
/**
* Handles the given audit event. The fall back implementation
* simply calls
* <code>AbstractExecutionObject.handleStateAuditEvent</code> if
* the event source is this object and the event is a
* <code>WfStateAuditEvent</code> or a
* <code>ToolCompletedAuditEvent</code> .
* @param event the event.
* @ejb.interface-method view-type="remote"
*/
public void handleAuditEvent (WfAuditEvent event) {
if (logger.isDebugEnabled()) {
logger.debug ("Got event: " + event.toString());
}
// Is this the target?
if (event.activityKey() == null) {
if (!(this instanceof AbstractProcess)
|| !event.processKey().equals(getPaKey())) {
return;
}
} else {
if (!(this instanceof AbstractActivity)
|| !event.activityKey().equals(getPaKey())) {
return;
}
}
if (event instanceof ToolInvocationFailedAuditEvent) {
handleToolInvocationFailedAuditEvent
((ToolInvocationFailedAuditEvent)event);
return;
}
if ((event instanceof WfStateAuditEvent)
|| (event instanceof ImplCompleteAuditEvent)) {
handleStateAuditEvent (event);
}
}
/**
* Handles a tool invocation failed audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleToolInvocationFailedAuditEvent
(ToolInvocationFailedAuditEvent event) {
}
/**
* Handles a state audit event, this includes
* <code>ImplCompleteAuditEvent</code>s. This implementation
* simply calls the appropriate handler method
* <code>handle<i>Transition</i>Event</code>.
* @param event the event.
*/
protected void handleStateAuditEvent (WfAuditEvent event) {
try {
if (event instanceof ImplCompleteAuditEvent) {
handleImplCompletedEvent ((ImplCompleteAuditEvent)event);
return;
}
WfStateAuditEvent evt = (WfStateAuditEvent)event;
State oldState = State.fromString (evt.oldState());
State newState = State.fromString (evt.newState());
if (oldState.isSameOrSubState(NotRunningState.NOT_STARTED)) {
if (newState == RunningState.RUNNING) {
handleStartedEvent (evt);
return;
}
if (newState == ClosedState.TERMINATED) {
handleTerminatedEvent (evt);
return;
}
} else if (oldState.isSameOrSubState(NotRunningState.SUSPENDED)) {
if (newState == RunningState.RUNNING) {
handleResumedEvent (evt);
return;
}
if (newState == ClosedState.ABORTED) {
handleAbortedEvent (evt);
return;
}
} else if (oldState.isSameOrSubState(OpenState.RUNNING)) {
if (newState == SuspendedState.SUSPENDED) {
handleSuspendedEvent (evt);
return;
}
if (newState == ClosedCompletedState.NORMAL) {
handleCompletedEvent (evt);
return;
}
if (newState == ClosedState.TERMINATED) {
handleTerminatedEvent (evt);
return;
}
}
logger.warn
("Cannot handle undefined state transition from "
+ oldState.toString() + " to " + newState.toString()
+ " for " + this);
} catch (InvalidStateException e) {
// can't do much about this, shouldn't happen
logger.error (e.getMessage(), e);
}
}
/**
* Handles a tool completed audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleImplCompletedEvent (ImplCompleteAuditEvent event) {
}
/**
* Handles a started audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleStartedEvent (WfStateAuditEvent event) {
}
/**
* Handles a terminated audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleTerminatedEvent (WfStateAuditEvent event) {
}
/**
* Handles a resumed audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleResumedEvent (WfStateAuditEvent event) {
}
/**
* Handles a aborting audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleAbortedEvent (WfStateAuditEvent event) {
}
/**
* Handles a suspended audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleSuspendedEvent (WfStateAuditEvent event) {
}
/**
* Handles a completed audit event. The default
* implementation does nothing.
* @param event the event.
*/
protected void handleCompletedEvent (WfStateAuditEvent event) {
}
}