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

com.atomikos.finitestates.FSMImp Maven / Gradle / Ivy

/**
 * Copyright (C) 2000-2023 Atomikos 
 *
 * LICENSE CONDITIONS
 *
 * See http://www.atomikos.com/Main/WhichLicenseApplies for details.
 */

package com.atomikos.finitestates;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import com.atomikos.recovery.TxState;


/**
 *
 *
 * Implementation of a finite state machine. The following
 * consistency is provided:
 * 
    *
  • getState returns a snapshot (state may change continuously)
  • *
  • FSMPreEnterListeners have the guarantee that getState() returns the same * value each time during the preEnter notification.
  • *
  • FSMEnterListeners have no guarantee that the getState() method will * return the state that was entered - this state may have changed since.
  • *
* */ public class FSMImp implements FSM { private TxState state_ = null; private final Hashtable> enterlisteners_ = new Hashtable<>(); private final Hashtable> transitionlisteners_ = new Hashtable<>(); private Object eventsource_ = null; private final Object stateLatch_ = new Object(); /** *Constructor. * *@param transitiontable The transitiontable with valid *transitions. * *@param initialstate The initial state of the FSM. */ public FSMImp ( TxState initialstate ) { this ( null, initialstate ); eventsource_ = this; } /** *Creates a new instance with a given event source. *Useful for cases where finite state machine behaviour is modelled *by delegation to an instance of this class. * *@param eventsource The object to be used as source of events. *@param transitiontable The transitiontable for state changes. *@param initialstate The initial state of the FSM. */ public FSMImp ( Object eventsource, TxState initialstate ) { state_ = initialstate; eventsource_ = eventsource; } /** *Notify the enter listeners. * *@param state The state about to enter (or entered). *@param pre True iff before entering. */ protected void notifyListeners(TxState state, boolean pre) { Set lstnrs = null; FSMEnterEvent event = new FSMEnterEvent (eventsource_, state); synchronized ( this ) { lstnrs = enterlisteners_.get ( state ); if ( lstnrs == null ) return; //clone to avoid concurrency effects outside synch block //during iteration hereafter lstnrs = new HashSet(lstnrs); } //notify OUTSIDE SYNCH to minimize deadlocks for (FSMEnterListener listener : lstnrs) { if ( pre ) { listener.preEnter(event); } else { listener.entered(event); } } } /** *Notify transition listeners. * *@param transition *@param pre True iff before transition. */ protected void notifyListeners(Transition transition, boolean pre) { FSMTransitionEvent event = new FSMTransitionEvent (eventsource_, transition); Set lstnrs = null; synchronized ( this ) { lstnrs = transitionlisteners_.get( transition ); if ( lstnrs == null ) { return; } //clone to avoid concurrency effects //during iteration outside synch block lstnrs = new HashSet(lstnrs); } //iterator outside synch to avoid deadlocks for (FSMTransitionListener listener : lstnrs) { if ( pre ) { listener.beforeTransition(event); } else { listener.transitionPerformed(event); } } } /** *@see com.atomikos.finitestates.FSM */ public TxState getState() { //Note: this method should NOT be synchronized on the FSM itself, to avoid deadlocks //in re-entrant 2PC calls! TxState ret = null; //don't synch on FSM -> use latch object instead synchronized ( stateLatch_ ) { ret = state_; } return ret; } private void setStateObject ( TxState state ) { //synchronize on stateLatch ONLY to make sure that getState //returns the latest (non-cached) value synchronized ( stateLatch_ ) { this.state_ = state; } } /** *@see com.atomikos.finitestates.StateMutable */ public void setState(TxState state) throws IllegalStateException { TxState oldstate = null; Transition transition = null; synchronized ( this ) { if (!state_.transitionAllowedTo(state)) { throw new IllegalStateException("Transition not allowed: "+state_ +" to "+state); } oldstate = state_; transition = new Transition(oldstate, state); notifyListeners(state , true); notifyListeners(transition , true); setStateObject ( state ); } //ENTER EVENTS ARE OUTSIDE SYNCH BLOCK TO MINIMIZE DEADLOCKS!!! notifyListeners(state , false); notifyListeners(transition, false); } /** *@see com.atomikos.finitestates.FSMEnterEventSource */ public synchronized void addFSMEnterListener(FSMEnterListener lstnr, TxState state) { Set lstnrs = enterlisteners_.get(state); if ( lstnrs == null ) { lstnrs = new HashSet(); enterlisteners_.put( state , lstnrs ); } if ( !lstnrs.contains(lstnr) ) { lstnrs.add(lstnr); } } /** *@see com.atomikos.finitestates.FSMTransitionEventSource */ public synchronized void addFSMTransitionListener(FSMTransitionListener listener, TxState from, TxState to) { Transition transition = new Transition(from, to); Set lstnrs = transitionlisteners_.get(transition); if (lstnrs == null) { lstnrs = new HashSet(); transitionlisteners_.put(transition, lstnrs); } if (!lstnrs.contains(listener)) { lstnrs.add(listener); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy