Apache SCXML 状态机

http://www.javacodegeeks.com/2012/06/apache-commons-scxml-finite-state.html

For full source code visit https://github.com/ozkansari/atmstatemachine

Apache Commons SCXML: Finite State Machine Implementation



atm_status.xml

<pre name="code" class="html"><scxml initial="idle" name="atm.connRestored" version="0.9" xmlns="http://www.w3.org/2005/07/scxml"><!--   node-size-and-position x=0.0 y=0.0 w=1050.0 h=590.0  -->
 <state id="idle"><!--   node-size-and-position x=40.0 y=220.0 w=100.0 h=100.0  -->
  <transition event="atm.connected" target="loading"></transition>
 </state>
 <state id="loading"><!--   node-size-and-position x=300.0 y=220.0 w=100.0 h=100.0  -->
  <transition event="atm.loadSuccess" target="inService"></transition>
  <transition event="atm.connClosed" target="disconnected"></transition>
  <transition event="atm.loadFail" target="outOfService"></transition>
 </state>
 <state id="inService"><!--   node-size-and-position x=570.0 y=30.0 w=100.0 h=100.0  -->
  <transition event="atm.shutdown" target="outOfService"><!--   edge-path [outOfService]  x=580.0 y=190.0 pointx=0.0 pointy=3.0 offsetx=-1.0 offsety=-2.0  --></transition>
  <transition event="atm.connLost" target="disconnected"><!--   edge-path [disconnected]  x=757.0 y=270.0 pointx=0.0 pointy=-12.0 offsetx=13.0 offsety=0.0  --></transition>
 </state>
 <state id="outOfService"><!--   node-size-and-position x=570.0 y=260.0 w=100.0 h=100.0  -->
  <transition event="atm.startup" target="inService"><!--   edge-path [inService]  x=660.0 y=190.0  --></transition>
  <transition event="atm.connLost" target="disconnected"></transition>
 </state>
 <state id="disconnected"><!--   node-size-and-position x=570.0 y=450.0 w=100.0 h=100.0  -->
  <transition event="atm.connRestored" target="inService"><!--   edge-path [inService]  x=860.0 y=275.0  --></transition>
 </state>
</scxml>




AtmStatusEventEnum.java

package net.javafun.example.atmstatusfsm;

public enum AtmStatusEventEnum {

	CONNECT("atm.connected"), 
	
	CONNECTION_CLOSED("atm.connClosed"),
	
	CONNECTION_LOST("atm.connLost"),
	
	CONNECTION_RESTORED("atm.connRestored"),
	
	LOAD_SUCCESS("atm.loadSuccess"),
	
	LOAD_FAIL("atm.loadFail"),
	
	SHUTDOWN("atm.shutdown"),
	
	STARTUP("atm.startup"),

	;
	
	private final String eventName;

	private AtmStatusEventEnum(String eventName) {
		this.eventName = eventName;
	}
	
	public String getEventName() {
		return eventName;
	}
	
	public static String getNamesAsCsv(){
		StringBuilder sb = new StringBuilder();
		for (AtmStatusEventEnum e : AtmStatusEventEnum.values()) {
			sb.append(e.name());
			sb.append(",");
		}
		return sb.substring(0,sb.length()-2);
	}
	
}

AtmStatusFSM.java

package net.javafun.example.atmstatusfsm;

import java.util.Collection;

import java.util.Set;

import org.apache.commons.scxml.env.AbstractStateMachine;
import org.apache.commons.scxml.model.State;

/**
 * Atm Status Finite State Machine Example
 * 
 * @see <a href="http://commons.apache.org/scxml/index.html "> Apache Commons Scxml Library </a>
 * @author ozkans
 *
 */
public class AtmStatusFSM extends AbstractStateMachine {

	/**
	 * State Machine uses this scmxml config file
	 */
//	private static final String SCXML_CONFIG_ATM_STATUS = "net/javafun/example/atmfsm/atm_status.xml";
	private static final String SCXML_CONFIG_ATM_STATUS = "atm_status.xml";

	
	/* ------------------------------------------------------------------------ */
	/* CONSTRUCTOR(S) */
	/* ------------------------------------------------------------------------ */
	
	public AtmStatusFSM() {
        	super(AtmStatusFSM.class.getClassLoader().getResource(SCXML_CONFIG_ATM_STATUS));
	}
	
	/* ------------------------------------------------------------------------ */
	/* HELPER METHOD(S) */
	/* ------------------------------------------------------------------------ */
	
	public void firePreDefinedEvent(AtmStatusEventEnum eventEnum){
		System.out.println("EVENT: " + eventEnum);
		this.fireEvent(eventEnum.getEventName());
	}
	
	public void callState(String name){
		this.invoke(name);
	}
	
	public String getCurrentStateId() {
		Set<?> states = getEngine().getCurrentStatus().getStates();
		State state = (State) states.iterator().next();
		return state.getId();
	}
	
	public State getCurrentState() {
		Set<?> states = getEngine().getCurrentStatus().getStates();
		return ( (State) states.iterator().next());
	}
	
	public Collection<?> getCurrentStateEvents() {
		return getEngine().getCurrentStatus().getEvents();
	}
	
	/* ------------------------------------------------------------------------ */
	// STATES
	// 
	// Each method below is the activity corresponding to a state in the
	// SCXML document (see class constructor for pointer to the document).
	/* ------------------------------------------------------------------------ */
	
	 public void idle() {
		System.out.println("STATE: idle 被触发");
	 }
	 
	 public void loading() {
		 System.out.println("STATE: loading 被触发");
	 }
	 
	 public void inService() {
		 System.out.println("STATE: inService 被触发");
	 }
	 
	 public void outOfService() {
		 System.out.println("STATE: outOfService 被触发");
	 }
	 
	 public void disconnected() {
		 System.out.println("STATE: disconnected 被触发");
	 }
}

用Java JFrame UI测试:

package net.javafun.example.atmstatusfsm;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import org.apache.commons.scxml.model.Transition;
import org.apache.commons.scxml.model.TransitionTarget;

public class AtmDisplay extends JFrame implements ActionListener {

	private static final long serialVersionUID = -5083315372455956151L;
	private AtmStatusFSM atmStatusFSM;

	private JButton button;
	private JLabel state;
	private JComboBox eventComboBox = new JComboBox();
	
	public static void main(String[] args) {
		new AtmDisplay();
	}
	
	public AtmDisplay() {
		super("ATM Display Demo");
		atmStatusFSM = new AtmStatusFSM();
		
		/*
		 //仅用作测试设置初始化状态,不设置的话使用atm_status.xml里面默认的初始状态
		@SuppressWarnings("unchecked")
		Map<String, TransitionTarget> mapTg = atmStatusFSM.getEngine().getStateMachine().getTargets();
		for(Map.Entry<String, TransitionTarget> entry : mapTg.entrySet()){
			System.out.println(entry.getKey() + " ==== " + entry.getValue().getId());
		}
		TransitionTarget tsTarget =  mapTg.get("inService");
		atmStatusFSM.getEngine().getStateMachine().setInitialTarget(tsTarget); //设置初始状态为inService
		atmStatusFSM.resetMachine();
		atmStatusFSM.fireEvent(AtmStatusEventEnum.SHUTDOWN.getEventName());
		*/
		setupUI();
	}

	@SuppressWarnings("deprecation")
	private void setupUI() {
		System.out.println("setupUI");
		JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		setContentPane(panel);
		button = makeButton("FIRE_EVENT", AtmStatusEventEnum.getNamesAsCsv(), "Submit" );
		panel.add(button, BorderLayout.CENTER);
		state = new JLabel(atmStatusFSM.getCurrentStateId());
		panel.add(state, BorderLayout.SOUTH);
		initEvents();
		panel.add(eventComboBox, BorderLayout.NORTH);
		pack();
		setLocation(200, 200);
		setResizable(false);
		setSize(300, 125);
		show();
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		
	}

	@SuppressWarnings("unchecked")
	private void initEvents() {
		System.out.println("initEvents");
		eventComboBox.removeAllItems();
		List<Transition> transitionList = atmStatusFSM.getCurrentState().getTransitionsList();
		for (Transition transition : transitionList) {
			eventComboBox.addItem(transition.getEvent() );
		}
	}

	public void actionPerformed(ActionEvent e) {
		System.out.println("actionPerformed");
		String command = e.getActionCommand();
		if(command.equals("FIRE_EVENT")) {
			checkAndFireEvent();
		}
	}

	private boolean checkAndFireEvent() {
		System.out.println("checkAndFireEvent");
		atmStatusFSM.fireEvent(eventComboBox.getSelectedItem().toString());
		state.setText(atmStatusFSM.getCurrentStateId());
		initEvents();
		repaint();
		return true;
	}

	private JButton makeButton(final String actionCommand, final String toolTipText, final String altText) {
		JButton button = new JButton(altText);
		button.setActionCommand(actionCommand);
		button.setToolTipText(toolTipText);
		button.addActionListener(this);
		button.setOpaque(false);
		return button;
	}

}


不用UI测试:

package net.javafun.example.atmstatusfsm;

import java.util.List;
import java.util.Map;

import org.apache.commons.scxml.model.Transition;
import org.apache.commons.scxml.model.TransitionTarget;

public class TestAtm {

	 
	public static void main(String[] args) {
		AtmStatusFSM atmStatusFSM = new AtmStatusFSM();
		setInitStatus(atmStatusFSM);  //仅用作测试设置初始化状态,不设置的话使用atm_status.xml里面默认的初始状态
		show(atmStatusFSM);
		show2(atmStatusFSM);
		//atmStatusFSM.fireEvent(AtmStatusEventEnum.CONNECT.getEventName()); //如果当前状态下没有该Event,那么不会出错,也不会fireEvent
		atmStatusFSM.fireEvent(AtmStatusEventEnum.SHUTDOWN.getEventName());
		//show2(atmStatusFSM);
	}
	
	private static void setInitStatus(AtmStatusFSM atmStatusFSM) {
		System.out.println("手动设置初始状态:");
		Map<String, TransitionTarget> mapTg = atmStatusFSM.getEngine().getStateMachine().getTargets();
		TransitionTarget tsTarget =  mapTg.get("inService");
		atmStatusFSM.getEngine().getStateMachine().setInitialTarget(tsTarget);
		atmStatusFSM.resetMachine();
		System.out.println();
	}

	@SuppressWarnings("unchecked")
	public static void show(AtmStatusFSM atmStatusFSM){		
		System.out.println("列出所有targets:");
		Map<String,TransitionTarget> mapTg = atmStatusFSM.getEngine().getStateMachine().getTargets();
		for(Map.Entry<String, TransitionTarget> entry : mapTg.entrySet()){
			System.out.println(entry.getKey() + " ==== " + entry.getValue().getId());
		}
		System.out.println("列出所有States:");
		Map<String,TransitionTarget> mapSt = atmStatusFSM.getEngine().getStateMachine().getStates();
		for(Map.Entry<String, TransitionTarget> entry : mapSt.entrySet()){
			System.out.println(entry.getKey() + " ==== " + entry.getValue().getId());
		}
		System.out.println();
	}
	
	public static void show2(AtmStatusFSM atmStatusFSM){
		System.out.println("列出当前状态及其所有target:");
		String currentStatus = atmStatusFSM.getCurrentStateId();
		System.out.println("currentStatus: " + currentStatus);
		System.out.println("currentStatus's all events: " );
	    //List<String> list =	atmStatusFSM.getCurrentStateEvents();
		List<Transition> transitionList = atmStatusFSM.getCurrentState().getTransitionsList();
		for (Transition transition : transitionList) {
			System.out.println(" " + transition.getEvent());
		}
		System.out.println();
	}

}










阅读更多
个人分类: Java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭