ステートチャート図をJavaアプリケーションで表現する

戻る
とりあえずモデルのみ。 あとでコントローラ、ビューを使って、GUIによる実装をします(予定)



■実行結果 $ java StateChartModel INITIAL_STATE: FINAL_STATE: PENDING: ACTIVE: DEACTIVE: CREATE_USER APPROVE_USER REJECT_USER ACTIVATE_USER DEACTIVATE_USER DELETE_USER [ INITIAL_STATE -> PENDING ] Successfully ended [ PENDING -> ACTIVE ] Successfully ended [ PENDING -> DEACTIVE ] Successfully ended [ DEACTIVE -> ACTIVE ] Successfully ended [ ACTIVE -> DEACTIVE ] Successfully ended [ DEACTIVE -> FINAL_STATE ] Successfully ended [ INITIAL_STATE -> INITIAL_STATE ] java.lang.Exception: 自分自身にはリンクできません at InitialState.connect(InitialState.java:25) at ConnectionAgent.connect(ConnectionAgent.java:15) at StateChartModel.connect(StateChartModel.java:124) at StateChartModel.main(StateChartModel.java:187) [ FINAL_STATE -> FINAL_STATE ] java.lang.Exception: 自分自身にはリンクできません at FinalState.connect(FinalState.java:25) at ConnectionAgent.connect(ConnectionAgent.java:15) at StateChartModel.connect(StateChartModel.java:124) at StateChartModel.main(StateChartModel.java:193) [ PENDING -> PENDING ] java.lang.Exception: 自分自身にはリンクできません at State.connect(State.java:28) at ConnectionAgent.connect(ConnectionAgent.java:15) at StateChartModel.connect(StateChartModel.java:124) at StateChartModel.main(StateChartModel.java:199) [ PENDING -> INITIAL_STATE ] java.lang.Exception: 他のステートから初期状態に対しては接続できません! at State.connect(State.java:32) at ConnectionAgent.connect(ConnectionAgent.java:15) at StateChartModel.connect(StateChartModel.java:124) at StateChartModel.main(StateChartModel.java:205) [ FINAL_STATE -> PENDING ] java.lang.Exception: 最終状態なので次のステートを設定できません at FinalState.connect(FinalState.java:28) at ConnectionAgent.connect(ConnectionAgent.java:15) at StateChartModel.connect(StateChartModel.java:124) at StateChartModel.main(StateChartModel.java:211) [ INITIAL_STATE -> PENDING ] java.lang.Exception: 既に同じ遷移が存在します at InitialState.connect(InitialState.java:22) at ConnectionAgent.connect(ConnectionAgent.java:15) at StateChartModel.connect(StateChartModel.java:124) at StateChartModel.main(StateChartModel.java:218) INITIAL_STATE: (CREATE_USER) -> PENDING FINAL_STATE: (DELETE_USER) <- DEACTIVE PENDING: (REJECT_USER) -> DEACTIVE (APPROVE_USER) -> ACTIVE (CREATE_USER) <- INITIAL_STATE ACTIVE: (DEACTIVATE_USER) -> DEACTIVE (ACTIVATE_USER) <- DEACTIVE (APPROVE_USER) <- PENDING DEACTIVE: (REJECT_USER) <- PENDING (DELETE_USER) -> FINAL_STATE (DEACTIVATE_USER) <- ACTIVE (ACTIVATE_USER) -> ACTIVE INITIAL_STATE: FINAL_STATE: PENDING: (REJECT_USER) -> DEACTIVE (APPROVE_USER) -> ACTIVE ACTIVE: (DEACTIVATE_USER) -> DEACTIVE (ACTIVATE_USER) <- DEACTIVE (APPROVE_USER) <- PENDING DEACTIVE: (REJECT_USER) <- PENDING (DEACTIVATE_USER) <- ACTIVE (ACTIVATE_USER) -> ACTIVE INITIAL_STATE: FINAL_STATE: ACTIVE: (DEACTIVATE_USER) -> DEACTIVE (ACTIVATE_USER) <- DEACTIVE DEACTIVE: (DEACTIVATE_USER) <- ACTIVE (ACTIVATE_USER) -> ACTIVE :::::::::::::: AbstractState.java :::::::::::::: import java.util.*; /** * $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ * @author KISHI Yasuhiro */ public abstract class AbstractState { /** 結合された遷移オブジェクト(transition)を格納するマップ */ protected Map transitionMap = new HashMap(); protected static int counter = 0; protected String name; /** コンストラクタ */ public AbstractState( String name ) { this.name = name; } /** コンストラクタ */ public AbstractState() {} protected String getName() { return name; } protected void setName( String name ) { this.name = name; } protected Map getTransitionMap() { return transitionMap; } protected void removeTransition( Transition transition ) { transitionMap.remove( transition ); } /** * <pre> * ステート同士を結合するための抽象メソッド * State, InitialState, FinalStateにより実装が異なる * </pre> */ protected abstract void connect( Transition transition, AbstractState state , Transition.Direction direction ) throws Exception; } :::::::::::::: Adjacence.java :::::::::::::: /** $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ @author KISHI Yasuhiro */ public class Adjacence { private AbstractState state; private Transition.Direction direction; public Adjacence( AbstractState state, Transition.Direction direction ) { this.state = state; this.direction = direction; } public AbstractState getState() { return state; } public Transition.Direction getDirection() { return direction; } } :::::::::::::: ConnectionAgent.java :::::::::::::: /** $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ @author KISHI Yasuhiro */ public class ConnectionAgent { public static void connect( Transition transition, AbstractState source, AbstractState destination ) throws Exception { System.out.println(); System.out.println( "[ " + source.getName() + " -> " + destination.getName() + " ]" ); try { source.connect( transition, destination, Transition.Direction.OUTGOING ); destination.connect( transition, source, Transition.Direction.INCOMING ); transition.setSourceState( source ); transition.setDestinationState( destination ); System.out.println( "\tSuccessfully ended" ); } catch ( Exception e ) { e.printStackTrace(); } } public static void disconnect( Transition transition ) throws Exception { AbstractState sourceState = transition.getSourceState(); AbstractState destinationState = transition.getDestinationState(); sourceState.removeTransition( transition ); destinationState.removeTransition( transition ); } } :::::::::::::: FinalState.java :::::::::::::: import java.util.*; /** * $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ * @author KISHI Yasuhiro */ public class FinalState extends AbstractState { private String name; public FinalState() { super( "FINAL_STATE" ); } public FinalState( String name ) { this.name = name; } protected void connect( Transition transition, AbstractState state, Transition.Direction direction ) throws Exception { if ( transitionMap.containsKey( transition ) ) { throw new Exception( "既に同じ遷移が存在します" ); } if ( state.equals( this ) ) { throw new Exception( "自分自身にはリンクできません" ); } if ( direction == Transition.Direction.OUTGOING ) { throw new Exception( "最終状態なので次のステートを設定できません" ); } // リンクする transitionMap.put( transition, new Adjacence( state, direction ) ); } } :::::::::::::: InitialState.java :::::::::::::: import java.util.*; /** * $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ * @author KISHI Yasuhiro */ public class InitialState extends AbstractState { private String name; public InitialState() { super( "INITIAL_STATE" ); } public InitialState( String name ) { super( name ); } protected void connect( Transition transition, AbstractState state, Transition.Direction direction ) throws Exception { if ( transitionMap.containsKey( transition ) ) { throw new Exception( "既に同じ遷移が存在します" ); } if ( state.equals( this ) ) { throw new Exception( "自分自身にはリンクできません" ); } if ( direction == Transition.Direction.INCOMING ) { throw new Exception( "初期状態なので前のステートを設定できません" ); } // リンクする transitionMap.put( transition, new Adjacence( state, direction ) ); } } :::::::::::::: State.java :::::::::::::: /** $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ @author KISHI Yasuhiro */ public class State extends AbstractState { public State( String name ) { super( name ); } public State() { super(); counter++; name = "state" + counter; } protected void connect( Transition transition, AbstractState state, Transition.Direction direction ) throws Exception { // この部分は本来ならfactory methodパターンでState, InitialState, FinalStateごとにファクトリクラスを作って対応したほうがいいかも! // ⇒重複コードを減らす if ( transitionMap.containsKey( transition ) ) { throw new Exception( "既に同じ遷移が存在します" ); } if ( state.equals( this ) ) { throw new Exception( "自分自身にはリンクできません" ); } if ( state instanceof InitialState && direction == Transition.Direction.OUTGOING ) { throw new Exception( "他のステートから初期状態に対しては接続できません!" ); } if ( state instanceof FinalState && direction == Transition.Direction.INCOMING ) { throw new Exception( "最終状態から他のステートへは接続できません!" ); } transitionMap.put( transition, new Adjacence( state, direction ) ); } } :::::::::::::: StateChartModel.java :::::::::::::: import java.util.*; /** * $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ * @author KISHI Yasuhiro * -- ステートチャートのモデル * 各モデルの関連を格納する(VIEWは持たない) */ public class StateChartModel { private String name; /** 初期状態 */ private InitialState initialState; /** 最終状態 */ private FinalState finalState; private List transitionList; private List stateList; /** コンストラクタ */ public StateChartModel( String name ) { this.name = name; createPreparedStates(); } /** コンストラクタ */ public StateChartModel() { createPreparedStates(); } private void createPreparedStates() { initialState = new InitialState(); finalState = new FinalState( ); addState( initialState ); addState( finalState ); } public void addState( AbstractState state ) { if ( stateList == null ) { stateList = new LinkedList(); } stateList.add( state ); } /** ステートを削除する */ public void removeState( AbstractState state ) throws Exception { Map map = state.getTransitionMap(); Iterator iterator = map.keySet().iterator(); List list = new ArrayList(); while ( iterator.hasNext() ) { Transition transition = ( Transition ) iterator.next(); list.add( transition ); } for ( int i = 0;i < list.size();i++ ) { Transition transition = ( Transition ) list.get( i ); ConnectionAgent.disconnect( transition ); } stateList.remove( state ); } public void addTransition( Transition transition ) { if ( transitionList == null ) { transitionList = new LinkedList(); } transitionList.add( transition ); } public InitialState getInitialState() { return initialState; } public FinalState getFinalState() { return finalState; } public void dumpStateList() { System.out.println(); Iterator iterator = stateList.iterator(); while ( iterator.hasNext() ) { AbstractState state = ( AbstractState ) iterator.next(); System.out.println( state.getName() + ":" ); // 対象ステートが保有するトランジションを一覧表示 Map map = state.getTransitionMap(); Iterator itrt = map.keySet().iterator(); while ( itrt.hasNext() ) { Transition transition = ( Transition ) itrt.next(); Adjacence adjacence = ( Adjacence ) map.get( transition ); AbstractState neighborState = adjacence.getState(); Transition.Direction direction = adjacence.getDirection(); System.out.print( "\t" ); System.out.print( "(" + transition.getName() + ")" ); if ( direction == Transition.Direction.OUTGOING ) { System.out.print( " -> " ); } if ( direction == Transition.Direction.INCOMING ) { System.out.print( " <- " ); } System.out.print( neighborState.getName() ); System.out.println( ); } } } public void dumpTransitionList() { Iterator iterator = transitionList.iterator(); while ( iterator.hasNext() ) { Transition transition = ( Transition ) iterator.next(); System.out.println( transition.getName() ); } } public void connect( Transition transition, AbstractState source, AbstractState destination ) throws Exception { ConnectionAgent.connect( transition, source, destination ); } public void disconnect( Transition transition ) throws Exception { ConnectionAgent.disconnect( transition ); } public static void main( String[] args ) { StateChartModel model = new StateChartModel( "User Account Management" ); InitialState initialState = model.getInitialState(); FinalState finalState = model.getFinalState(); // StateをStateChartModelに紐付けする State pending = new State( "PENDING" ); State active = new State( "ACTIVE" ); State deactive = new State( "DEACTIVE" ); model.addState( pending ); model.addState( active ); model.addState( deactive ); model.dumpStateList(); System.out.println(); // TransitionをStateChartModelに紐付けする Transition createUser = new Transition( "CREATE_USER" ); Transition approveUser = new Transition( "APPROVE_USER" ); Transition rejectUser = new Transition( "REJECT_USER" ); Transition activateUser = new Transition( "ACTIVATE_USER" ); Transition deactivateUser = new Transition( "DEACTIVATE_USER" ); Transition deleteUser = new Transition( "DELETE_USER" ); model.addTransition( createUser ); model.addTransition( approveUser ); model.addTransition( rejectUser ); model.addTransition( activateUser ); model.addTransition( deactivateUser ); model.addTransition( deleteUser ); model.dumpTransitionList(); System.out.println(); //===================================================== // 正常系 //===================================================== try { model.connect( createUser, initialState, pending ); model.connect( approveUser, pending, active ); model.connect( rejectUser, pending, deactive ); model.connect( activateUser, deactive, active ); model.connect( deactivateUser, active, deactive ); model.connect( deleteUser, deactive, finalState ); } catch ( Exception e ) { e.printStackTrace(); } //===================================================== // 異常系 //===================================================== try { model.connect( new Transition( "EXCEPTION1" ), initialState, initialState ); } catch ( Exception e ) { e.printStackTrace(); } try { model.connect( new Transition( "EXCEPTION2" ), finalState, finalState ); } catch ( Exception e ) { e.printStackTrace(); } try { model.connect( new Transition( "EXCEPTION3" ), pending, pending ); } catch ( Exception e ) { e.printStackTrace(); } try { model.connect( new Transition( "EXCEPTION4" ), pending, initialState ); } catch ( Exception e ) { e.printStackTrace(); } try { model.connect( new Transition( "EXCEPTION5" ), finalState, pending ); } catch ( Exception e ) { e.printStackTrace(); } // In case when there is an already-existing transition try { model.connect( createUser, initialState, pending ); } catch ( Exception e ) { e.printStackTrace(); } // リンク設定後の内容をダンプする model.dumpStateList(); System.out.println(); // リンク解除の試験 try { model.disconnect( createUser ); model.disconnect( deleteUser ); } catch ( Exception e ) { e.printStackTrace(); } // ダンプする model.dumpStateList(); System.out.println(); // ステートの削除 try { model.removeState( pending ); } catch ( Exception e ) { e.printStackTrace(); } // ダンプする model.dumpStateList(); System.out.println(); } } :::::::::::::: Transition.java :::::::::::::: import java.util.*; /** * $Id: StateChartDiagram.html,v 1.1 2009/06/22 16:11:57 kishi Exp kishi $ * @author KISHI Yasuhiro */ public class Transition { public static enum Direction {INCOMING, OUTGOING} private String name; private AbstractState sourceState; private AbstractState destinationState; public Transition( String name ) { this.name = name; } public String getName() { return name; } public void setSourceState( AbstractState sourceState ) { this.sourceState = sourceState; } public void setDestinationState( AbstractState destinationState ) { this.destinationState = destinationState; } public AbstractState getSourceState() { return sourceState; } public AbstractState getDestinationState() { return destinationState; } }
戻る inserted by FC2 system