package org.zstack.core.statemachine; import org.zstack.header.exception.CloudStateMachineException; import org.zstack.utils.Utils; import org.zstack.utils.logging.CLogger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class StateMachineImpl<T extends Enum<T>, K extends Enum<K>> implements StateMachine<T, K> { private Map<T, HashMap<K, T>> _chart = new HashMap<T, HashMap<K, T>>(); private List<StateMachineListener<T, K>> _listeners = new ArrayList<StateMachineListener<T, K>>(); private List<StateMachineListener<T, K>> _listenersTmp = new ArrayList<StateMachineListener<T, K>>(); private static final CLogger _logger = Utils.getLogger(StateMachineImpl.class); @Override public void addTranscation(T old, K evt, T next) { HashMap<K, T> entry = _chart.get(old); if (entry == null) { entry = new HashMap<K, T>(1); _chart.put(old, entry); } entry.put(evt, next); } @Override public T getNextState(T old, K evt) { HashMap<K, T> entry = _chart.get(old); if (entry == null) { StringBuilder err = new StringBuilder("Cannot find next state:"); err.append("[old state: ").append(old).append(","); err.append(" state event: ").append(evt).append("]"); throw new CloudStateMachineException(err.toString()); } T next = entry.get(evt); if (next == null) { StringBuilder err = new StringBuilder("Cannot find next state:"); err.append("[old state: ").append(old).append(","); err.append(" state event: ").append(evt).append("]"); throw new CloudStateMachineException(err.toString()); } return next; } @Override public void addListener(StateMachineListener<T, K> l) { synchronized (_listeners) { _listeners.add(l); } } @Override public void removeListener(StateMachineListener<T, K> l) { synchronized (_listeners) { _listeners.remove(l); } } @Override public void fireBeforeListener(T old, K evt, T next, Object... args) { _listenersTmp.clear(); synchronized (_listeners) { _listenersTmp.addAll(_listeners); } for (StateMachineListener<T, K> l : _listenersTmp) { try { l.before(old, evt, next, args); } catch (Exception e) { StringBuilder err = new StringBuilder("Unhandled exception while calling listener: " + l.getClass().getCanonicalName()); err.append( " before state changing.").append("[").append("current state:" + old).append(" event: " + evt); err.append(" next state: " + next).append("]"); _logger.warn(err.toString(), e); } } } @Override public void fireAfterListener(T prev, K evt, T curr, Object... args) { _listenersTmp.clear(); synchronized (_listeners) { _listenersTmp.addAll(_listeners); } for (StateMachineListener<T, K> l : _listenersTmp) { try { l.after(prev, evt, curr, args); } catch (Exception e) { StringBuilder err = new StringBuilder("Unhandled exception while calling listener: " + l.getClass().getCanonicalName()); err.append( " after state changing.").append("[").append("previous state:" + prev).append(" event: " + evt); err.append(" current state: " + curr).append("]"); _logger.warn(err.toString(), e); } } } }