ステートチャート図を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;
}
}
戻る