Skip to content

Latest commit

Β 

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

JFSM

Java Finite State Machine (FSM) Manager

JFSM은 μžλ°” 기반의 κ²½λŸ‰ μƒνƒœ λ¨Έμ‹ (Finite State Machine) ν”„λ ˆμž„μ›Œν¬μž…λ‹ˆλ‹€. κ°„κ²°ν•œ API둜 μƒνƒœ 천이(transition)λ₯Ό μ •μ˜ν•˜κ³ , 콜백과 쑰건(EventCondition), μ§€μ—° μ‹€ν–‰ 및 μž¬μ‹œλ„(Retry) 같은 싀무 μΉœν™” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. λ©€ν‹° μŠ€λ ˆλ“œ 기반의 νƒœμŠ€ν¬ μ‹€ν–‰κΈ°(StateTaskManager)λ₯Ό 톡해 비동기/μ§€μ—° 이벀트 μ²˜λ¦¬λ„ μ‰½κ²Œ ꡬ성할 수 μžˆμŠ΅λ‹ˆλ‹€.

  • μ΅œμ†Œ μ˜μ‘΄μ„±, 순수 μžλ°”λ‘œ λ™μž‘
  • κ°„λ‹¨ν•œ DSL μŠ€νƒ€μΌμ˜ μƒνƒœ 천이 등둝 API
  • 천이 성곡/μ‹€νŒ¨ 콜백, λ‹€μŒ 이벀트 체이닝(nextEvent)
  • μ§€μ—°(delay) 및 μž¬μ‹œλ„(nextEventRetryCount) 지원
  • 쑰건뢀 μ‹€ν–‰(EventCondition) 및 μŠ€μΌ€μ€„λ§ 지원
  • λ©€ν‹° μŠ€λ ˆλ“œ νƒœμŠ€ν¬ 처리(StateTaskManager)와 μ•ˆμ „ν•œ λ™μ‹œμ„± μ œμ–΄

STRUCTURE

스크란샷 2022-01-28 α„‹α…©α„Œα…₯ᆫ 10 26 24

전체 μ»΄ν¬λ„ŒνŠΈ ꡬ쑰 λ‹€μ΄μ–΄κ·Έλž¨

flowchart TB
  subgraph JFSM["JFSM Core"]
    SM["StateManager<br/>- FSM μ΅œμƒμœ„ λ§€λ‹ˆμ €<br/>- μŠ€λ ˆλ“œν’€/νƒœμŠ€ν¬κ΄€λ¦¬<br/>- Handler 등둝/쑰회/μ‚­μ œ"]
    SH["StateHandler<br/>- 도메인 κ·Έλ£Ή(μœ ν˜•) λ‹¨μœ„<br/>- μƒνƒœ/이벀트/전이 등둝 API 제곡"]
    SEM["StateEventManager<br/>- 전이 ν…Œμ΄λΈ”(Transition) 관리<br/>- 이벀트 처리 μ‹€ν–‰ 둜직"]
    SU["StateUnit<br/>- μ‹€μ œ μƒνƒœλ₯Ό κ°€μ§„ μ—”ν‹°ν‹°<br/>(μ„Έμ…˜/μ£Όλ¬Έ/μž₯λΉ„ λ“±)"]
    ST["StateTaskManager<br/>- λ©€ν‹° μŠ€λ ˆλ“œ νƒœμŠ€ν¬ μ‹€ν–‰κΈ°<br/>- 비동기/μ§€μ—° 이벀트 처리"]
    EC["EventCondition<br/>- 전이 μ‹€ν–‰ μ „ 쑰건 검사"]
    CB["CallBack<br/>- 전이 성곡/μ‹€νŒ¨ ν›„μ²˜λ¦¬"]
    RM["RetryManager<br/>- μž¬μ‹œλ„ μ •μ±…/μƒνƒœ 관리"]
  end

  SM --> SH
  SH --> SEM
  SEM --> SU

  SEM --> EC
  SEM --> CB
  SEM --> RM

  SM --> ST
  ST --> SEM
Loading

이벀트 처리 흐름(쑰건 β†’ 전이 β†’ 콜백 β†’ nextEvent/μ§€μ—°/μž¬μ‹œλ„)

flowchart TB
  IN["μž…λ ₯: (StateUnit, Event)"] --> H["StateHandler<br/>도메인 κ·Έλ£Ή 선택"]
  H --> EM["StateEventManager<br/>전이 ν…Œμ΄λΈ” 쑰회"]
  EM --> COND{"EventCondition<br/>쑰건 톡과?"}

  COND -->|예| TRANS["Transition μ‹€ν–‰<br/>StateUnit μƒνƒœ λ³€κ²½"]
  COND -->|μ•„λ‹ˆμ˜€| FAILCB["Fail CallBack<br/>μ‹€νŒ¨ ν›„μ²˜λ¦¬"]

  TRANS --> SUCCB["Success CallBack<br/>성곡 ν›„μ²˜λ¦¬"]
  SUCCB --> NEXT{"nextEvent 쑴재?"}

  NEXT -->|μ•„λ‹ˆμ˜€| DONE["μ’…λ£Œ"]
  NEXT -->|예| DELAY{"delay μ„€μ •?"}
  DELAY -->|μ—†μŒ| DISPATCH["μ¦‰μ‹œ λ‹€μŒ 이벀트 λ””μŠ€νŒ¨μΉ˜"]
  DELAY -->|있음| SCHED["StateTaskManager<br/>μ§€μ—° μŠ€μΌ€μ€„λ§"]

  SCHED --> DISPATCH
  DISPATCH --> RETRY{"nextEventRetryCount μ„€μ •?"}
  RETRY -->|μ—†μŒ| EM2["StateEventManager<br/>λ‹€μŒ 이벀트 처리"]
  RETRY -->|있음| RM["RetryManager<br/>μž¬μ‹œλ„ μƒνƒœ/횟수 관리"]
  RM --> EM2

  EM2 --> COND
Loading

μ‹œν€€μŠ€ λ‹€μ΄μ–΄κ·Έλž¨(ν΄λΌμ΄μ–ΈνŠΈ 관점 호좜 β†’ λ‚΄λΆ€ 처리)

sequenceDiagram
  autonumber
  participant C as Client Code
  participant SM as StateManager
  participant SH as StateHandler
  participant EM as StateEventManager
  participant EC as EventCondition
  participant SU as StateUnit
  participant CB as CallBack
  participant ST as StateTaskManager
  participant RM as RetryManager

  C->>SM: addStateHandler("ATM")<br/>ν•Έλ“€λŸ¬ 등둝
  C->>SM: getStateHandler("ATM")<br/>ν•Έλ“€λŸ¬ 쑰회
  C->>SH: addState(...)<br/>전이/콜백/nextEvent/delay/retry 등둝
  C->>SM: addStateUnit(unit)<br/>μƒνƒœ μœ λ‹› 등둝
  C->>SM: fireEvent(unit, event)<br/>이벀트 μ‹€ν–‰(κ°œλ…μ )

  SM->>SH: 도메인 ν•Έλ“€λŸ¬λ‘œ λΌμš°νŒ…
  SH->>EM: 전이 ν…Œμ΄λΈ” 쑰회/μ‹€ν–‰ μš”μ²­
  EM->>EC: 쑰건 검사
  alt 쑰건 톡과
    EM->>SU: μƒνƒœ λ³€κ²½(Prev/Cur)
    EM->>CB: Success CallBack
    alt nextEvent 쑴재
      alt delay 쑴재
        EM->>ST: μ§€μ—° μ‹€ν–‰ μŠ€μΌ€μ€„λ§
        ST-->>EM: (μ‹œκ°„ ν›„) nextEvent μ‹€ν–‰ 트리거
      else delay μ—†μŒ
        EM-->>EM: μ¦‰μ‹œ nextEvent μ‹€ν–‰
      end
      alt retry μ„€μ •
        EM->>RM: μž¬μ‹œλ„ μƒνƒœ κ°±μ‹ /κ°μ†Œ
      end
    end
  else 쑰건 μ‹€νŒ¨
    EM->>CB: Fail CallBack
  end
Loading

μƒνƒœ λ¨Έμ‹  관점(β€œμƒνƒœ 전이 ν…Œμ΄λΈ”β€μ„ μ“°λŠ” 이유λ₯Ό κ·ΈλŒ€λ‘œ ν‘œν˜„)

stateDiagram-v2
  [*] --> REGISTERED: StateUnit 등둝
  REGISTERED --> READY: 초기 μƒνƒœ μ„€μ •

  READY --> RUNNING: Event λ°œμƒ<br/>전이 ν…Œμ΄λΈ” λ§€μΉ­
  RUNNING --> READY: Success CallBack<br/>nextEvent μ—†μŒ

  RUNNING --> WAITING: nextEvent + delay
  WAITING --> RUNNING: μ§€μ—° μ‹œκ°„ 도달<br/>StateTaskManager μ‹€ν–‰

  RUNNING --> RETRYING: μ‹€νŒ¨/쑰건 뢈만쑱<br/>retry μ„€μ •
  RETRYING --> RUNNING: μž¬μ‹œλ„(횟수 λ‚¨μŒ)
  RETRYING --> FAILED: μž¬μ‹œλ„ μ†Œμ§„

  FAILED --> [*]
Loading

μ†Œκ°œ

JFSM은 λ‹€μŒκ³Ό 같은 상황에 μœ μš©ν•©λ‹ˆλ‹€.

  • μ‚¬μš©μž/업무 흐름을 λͺ…ν™•νžˆ μƒνƒœλ‘œ λͺ¨λΈλ§ν•˜κ³  싢은 경우
  • 이벀트 기반으둜 단계별 μ²˜λ¦¬μ™€ μ—λŸ¬ 볡ꡬ/μž¬μ‹œλ„λ₯Ό ν•˜κ³  싢은 경우
  • λ©€ν‹° μŠ€λ ˆλ“œμ—μ„œ λ‹€μˆ˜μ˜ μƒνƒœ 객체λ₯Ό μ•ˆμ „ν•˜κ²Œ κ΄€λ¦¬ν•˜κ³  싢은 경우

ꡬ성 μš”μ†ŒλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • StateManager: FSM 전체λ₯Ό κ΄€λ¦¬ν•˜λŠ” μƒμœ„ λ§€λ‹ˆμ €. μŠ€λ ˆλ“œ ν’€ 크기, ν•Έλ“€λŸ¬/μœ λ‹› 등둝/μ‚­μ œ λ“± 제곡
  • StateHandler: νŠΉμ • 도메인(μœ ν˜•)의 μ΄λ²€νŠΈμ™€ 천이λ₯Ό 관리
  • StateEventManager: 천이 ν…Œμ΄λΈ”κ³Ό μ‹€ν–‰ λ‘œμ§μ„ λ‹΄λ‹Ή
  • StateUnit: μ‹€μ œλ‘œ μƒνƒœλ₯Ό κ°–κ³  이벀트λ₯Ό μ μš©λ°›λŠ” 개체(μ„Έμ…˜/μ£Όλ¬Έ/μž₯λΉ„ λ“±)
  • EventCondition: 천이 μ‹€ν–‰ μ „ 쑰건 검사 μΈν„°νŽ˜μ΄μŠ€
  • CallBack: 천이 성곡/μ‹€νŒ¨ μ‹œμ  ν›„μ²˜λ¦¬ 콜백 μΈν„°νŽ˜μ΄μŠ€
  • RetryManager: μž¬μ‹œλ„ μ •μ±… 및 μƒνƒœ 관리 μœ ν‹Έ

UML κ°œμš”(μ˜ˆμ‹œ):

  • FSM: JFSM/src/main/resources/uml/fsm_uml.puml
  • ATM 데λͺ¨: JFSM/src/test/java/atm/uml/atm_state.puml

μ™œ FSM인가 (λ„μž… λ°°κ²½κ³Ό 이점)

ν˜„λŒ€ μ„œλΉ„μŠ€λŠ” μ‚¬μš©μž 흐름, 주문·결제, κΈ°κΈ° μ œμ–΄(예: ATM) λ“± 단계적 둜직이 λ§ŽμŠ΅λ‹ˆλ‹€. 이 흐름을 if-else/switch, 타이머, μŠ€λ ˆλ“œ, 큐 둜직으둜 즉ν₯ κ΅¬ν˜„ν•˜λ©΄ μ½”λ“œκ°€ λΉ λ₯΄κ²Œ λ³΅μž‘ν•΄μ§€κ³  결합도가 λ†’μ•„μ§‘λ‹ˆλ‹€. FSM(Finite State Machine)은 μ‹œμŠ€ν…œμ˜ κ°€λŠ₯ν•œ μƒνƒœμ™€ 이벀트, 전이λ₯Ό λͺ…ν™•νžˆ μ •μ˜ν•΄ λ‹€μŒκ³Ό 같은 이점을 μ œκ³΅ν•©λ‹ˆλ‹€.

  • λ³΅μž‘λ„ 관리와 가독성 ν–₯상
    • μƒνƒœμ™€ 전이(transition)λ₯Ό ν‘œλ‘œ κ΄€λ¦¬ν•˜λ―€λ‘œ 흐름이 λͺ…ν™•ν•©λ‹ˆλ‹€.
    • "μ–΄λ–€ μ΄λ²€νŠΈκ°€ μ–΄λ–€ μƒνƒœμ—μ„œ μœ νš¨ν•œκ°€"λ₯Ό μ½”λ“œ λ ˆλ²¨μ—μ„œ κ°•μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ‹ λ’°μ„± μžˆλŠ” 였λ₯˜ μ²˜λ¦¬μ™€ 회볡λ ₯
    • 성곡/μ‹€νŒ¨ 콜백으둜 ν›„μ²˜λ¦¬λ₯Ό μΌκ΄€λ˜κ²Œ μˆ˜ν–‰ν•©λ‹ˆλ‹€.
    • nextEvent + delay + nextEventRetryCount둜 μ‹€νŒ¨ ν›„ μž¬μ‹œλ„Β·λ°±μ˜€ν”„Β·λŒ€κΈ° 같은 회볡 μ „λž΅μ„ μ„ μ–Έμ μœΌλ‘œ ꡬ성할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ™μ‹œμ„± μ œμ–΄μ™€ 비동기 처리의 λ‹¨μˆœν™”
    • StateTaskManagerκ°€ μ§€μ—° μ‹€ν–‰κ³Ό 체이닝을 μŠ€λ ˆλ“œ ν’€μ—μ„œ μ•ˆμ „ν•˜κ²Œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.
    • 이벀트 쑰건(EventCondition)으둜 경쟁 μ‘°κ±΄μ΄λ‚˜ μœ νš¨μ„± 선검사λ₯Ό μ€‘μ•™ν™”ν•©λ‹ˆλ‹€.
  • ν…ŒμŠ€νŠΈ μš©μ΄μ„±κ³Ό 좔적 κ°€λŠ₯μ„±
    • 각 전이와 콜백이 독립 λͺ¨λ“ˆμ΄λ―€λ‘œ λ‹¨μœ„ ν…ŒμŠ€νŠΈκ°€ μ‰½μŠ΅λ‹ˆλ‹€.
    • μƒνƒœ 이λ ₯(Prev/Cur)으둜 μΌ€μ΄μŠ€ μž¬ν˜„κ³Ό μž₯μ•  뢄석이 μš©μ΄ν•©λ‹ˆλ‹€.
  • 도메인 μ •ν•©μ„±κ³Ό ν™•μž₯μ„±
    • 도메인 μ–Έμ–΄(예: READY β†’ CARD_READ β†’ PIN_ENTRY)λ₯Ό κ·ΈλŒ€λ‘œ μ½”λ“œμ— λ°˜μ˜ν•΄ μ˜μ‚¬μ†Œν†΅μ΄ μ‰¬μ›Œμ§‘λ‹ˆλ‹€.
    • μƒˆλ‘œμš΄ μƒνƒœ/이벀트 μΆ”κ°€κ°€ κΈ°μ‘΄ μ½”λ“œμ— μ΅œμ†Œν•œμ˜ 영ν–₯으둜 κ°€λŠ₯ν•©λ‹ˆλ‹€.

JFSM이 μ œκ³΅ν•˜λŠ” κΈ°λŠ₯은 FSM λ„μž… 효과λ₯Ό 싀무에 맞게 κ°•ν™”ν•©λ‹ˆλ‹€.

  • 선언적 API: StateHandler.addState(...)둜 전이, 콜백, λ‹€μŒ 이벀트, μ§€μ—°, μž¬μ‹œλ„κΉŒμ§€ ν•œ λ²ˆμ— μ •μ˜
  • 쑰건뢀 μ‹€ν–‰: EventCondition으둜 사전 검증 λ‘œμ§μ„ ν”ŒλŸ¬κ·ΈμΈμ²˜λŸΌ μΆ”κ°€
  • λΉ„λ™κΈ°Β·μŠ€μΌ€μ€„λ§: λ‚΄λΆ€ μŠ€μΌ€μ€„λŸ¬/μŠ€λ ˆλ“œν’€ 기반으둜 λ‹€μŒ 이벀트 μžλ™ 처리
  • μž¬μ‹œλ„ μ „λž΅: RetryManagerλ₯Ό 톡해 λ‹¨μˆœ λ°˜λ³΅λΆ€ν„° μ œν•œ νšŸμˆ˜Β·μ§€μ—° κ°„κ²©κΉŒμ§€ μœ μ—°ν•˜κ²Œ ꡬ성

μ–Έμ œ FSM을 μ“°μ§€ μ•Šμ•„λ„ λ˜λŠ”κ°€?

  • 전이가 1~2개 μˆ˜μ€€μ˜ μ•„μ£Ό λ‹¨μˆœν•œ ν”Œλ‘œμš°
  • μƒνƒœ κ°œλ…μ΄ 거의 μ—†κ³  μ ˆμ°¨ν˜• 직선 둜직으둜 μΆ©λΆ„ν•œ 경우 이런 κ²½μš°μ—λŠ” 였히렀 FSM이 과섀계가 될 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μƒνƒœ/μ΄λ²€νŠΈκ°€ λŠ˜μ–΄λ‚˜κ³  λΉ„λ™κΈ°Β·μ§€μ—°Β·μž¬μ‹œλ„κ°€ μ–½νžˆλ©΄ FSM이 μž₯κΈ° μœ μ§€λ³΄μˆ˜ κ΄€μ μ—μ„œ μœ λ¦¬ν•©λ‹ˆλ‹€.

λΉ λ₯Έ μ‹œμž‘

μ•„λž˜λŠ” μ΅œμ†Œ ꡬ성 μ˜ˆμ‹œμž…λ‹ˆλ‹€.

import com.fsm.StateManager;
import com.fsm.module.StateHandler;
import com.fsm.event.base.CallBack;

// 1) FSM λ§€λ‹ˆμ € 생성 (νƒœμŠ€ν¬ μŠ€λ ˆλ“œ μ΅œλŒ€ 개수 μ§€μ •)
StateManager fsm = new StateManager(4);

// 2) ν•Έλ“€λŸ¬ 등둝 (도메인 κ·Έλ£Ήλͺ…)
fsm.addStateHandler("ATM");
StateHandler handler = fsm.getStateHandler("ATM");

// 3) μƒνƒœ μœ λ‹› 등둝 (μ‹€μ œ μƒνƒœλ₯Ό κ°€μ§„ 개체)
fsm.addStateUnit("acct-001", "ATM", "INIT", new Object());

// 4) 천이 μ •μ˜ (event, from, to, μ„±κ³΅μ½œλ°±, μ‹€νŒ¨μ½œλ°±, λ‹€μŒμ΄λ²€νŠΈ, μ§€μ—°(ms), μž¬μ‹œλ„)
CallBack ok = (unit, params) -> {
    System.out.println("on success: " + unit.getName());
    return true;
};
CallBack fail = (unit, params) -> {
    System.out.println("on fail: " + unit.getName());
    return true;
};

handler.addState(
    "INPUT_PIN",          // event
    "INIT",               // from
    "PIN_ENTERED",        // to
    ok,                    // success callback
    fail,                  // fail callback
    "SELECT_MENU",        // next event (체이닝)
    0,                     // delay (ms)
    0                      // retry count
);

// 5) 이벀트 μ‹€ν–‰
var unit = fsm.getStateUnit("acct-001");
String nextState = handler.fire("INPUT_PIN", unit);
System.out.println("Next State: " + nextState);

// μ’…λ£Œ μ‹œ
fsm.stop();

핡심 κ°œλ…

  • StateManager
    • FSM 전체 수λͺ…κ³Ό λ¦¬μ†ŒμŠ€λ₯Ό κ΄€λ¦¬ν•©λ‹ˆλ‹€.
    • ν•Έλ“€λŸ¬(StateHandler)와 μœ λ‹›(StateUnit)을 등둝/μ‚­μ œν•©λ‹ˆλ‹€.
    • 내뢀에 StateTaskManagerλ₯Ό λ³΄μœ ν•˜λ©°, 비동기 μž‘μ—…μ„ μ‹€ν–‰ν•©λ‹ˆλ‹€.
  • StateHandler
    • 이벀트 천이 μ •μ˜λ₯Ό λ“±λ‘ν•˜κ³ , fire/handle둜 μ‹€ν–‰ν•©λ‹ˆλ‹€.
    • 동일 ν•Έλ“€λŸ¬ λ‚΄ 이벀트 κ°„ 체이닝(nextEvent)κ³Ό 지연을 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • StateEventManager
    • 천이 ν…Œμ΄λΈ”μ„ μ €μž₯ν•˜κ³  μ‹€ν–‰ λ‘œμ§μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€.
    • 성곡/μ‹€νŒ¨ 콜백, μž¬μ‹œλ„, 쑰건 검사 등을 μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜ν•©λ‹ˆλ‹€.
  • StateUnit
    • 이름, ν˜„μž¬ μƒνƒœ, λΆ€κ°€ 데이터(payload)λ₯Ό κ°–λŠ” FSM의 λŒ€μƒ κ°μ²΄μž…λ‹ˆλ‹€.
  • EventCondition
    • νŠΉμ • 이벀트 μ‹€ν–‰ μ „ 쑰건을 κ²€μ¦ν•©λ‹ˆλ‹€.
    • μ‹€νŒ¨/였λ₯˜ 상황 μ‹œ λ‹€μŒ μ²œμ΄λ‚˜ 콜백 λ™μž‘μ— 영ν–₯을 쀄 수 μžˆμŠ΅λ‹ˆλ‹€.
  • CallBack
    • 천이 성곡/μ‹€νŒ¨ μ‹œμ μ— ν›„μ²˜λ¦¬λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.
  • Retry(μž¬μ‹œλ„)
    • nextEventRetryCount둜 λ‹€μŒ 이벀트 체이닝 μ‹œ μž¬μ‹œλ„ 횟수λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€.

μ‚¬μš© 방법

1) StateManager 생성

StateManager fsm = new StateManager(4); // μŠ€λ ˆλ“œ μ΅œλŒ€ 4개

2) StateHandler 등둝 및 쑰회

fsm.addStateHandler("ORDER");
StateHandler handler = fsm.getStateHandler("ORDER");

3) StateUnit 등둝/μ‚­μ œ/쑰회

fsm.addStateUnit("order-1001", "ORDER", "NEW", payload);
fsm.getStateUnit("order-1001");
fsm.removeStateUnit("order-1001");

4) 천이 μ •μ˜ API

μ˜€λ²„λ‘œλ“œ 두 κ°€μ§€κ°€ μ œκ³΅λ©λ‹ˆλ‹€.

  • 단일 from μƒνƒœμ—μ„œ to둜 천이
  • 닀쀑 from μƒνƒœ μ§‘ν•©μ—μ„œ to둜 천이
boolean added = handler.addState(
    "PAY",                 // event
    "NEW",                 // fromState
    "PAID",                // toState
    successCb, failCb,
    null,                   // nextEvent μ—†μœΌλ©΄ null
    0,                      // delay
    0,                      // retry count
    new Object[]{/* next params */}
);
HashSet<String> from = new HashSet<>(List.of("NEW", "RETRY"));
boolean added = handler.addState(
    "PAY",                 // event
    from,                   // fromStateSet
    "PAID",                // toState
    successCb, failCb,
    "SHIP",                // nextEvent
    1000,                   // delay 1s ν›„ nextEvent
    3,                      // μ΅œλŒ€ 3회 μž¬μ‹œλ„
    "param1", 123
);

5) μ‹€ν–‰

String nextState = handler.fire("PAY", stateUnit);

κ³ κΈ‰ 주제

μ§€μ—°κ³Ό 체이닝(nextEvent)

  • addState에 nextEvent, delayλ₯Ό μ§€μ •ν•˜λ©΄ 성곡 μ‹œ λ‹€μŒ 이벀트λ₯Ό μ§€μ—° ν›„ μžλ™ μ‹€ν–‰ν•©λ‹ˆλ‹€.
  • nextEventRetryCount둜 μ‹€νŒ¨ μ‹œ μž¬μ‹œλ„ 횟수λ₯Ό μ œμ–΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

쑰건(EventCondition)

EventCondition을 ν•Έλ“€λŸ¬μ— 등둝해 이벀트 μ‹€ν–‰ μ „ 검증을 μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

handler.addEventCondition((event, unit) -> {
    // μ‹€ν–‰ κ°€λŠ₯ μ—¬λΆ€ 검사 (true=톡과)
    return unit != null && unit.getIsAlive();
}, 0); // delay(ms) β€” ν•„μš” μ‹œ 쑰건도 μ§€μ—° 평가 κ°€λŠ₯

비동기/λ©€ν‹°μŠ€λ ˆλ“œ

  • StateTaskManager와 λ‚΄λΆ€ μŠ€μΌ€μ€„λŸ¬κ°€ μ§€μ—°/체이닝 μž‘μ—…μ„ λ°±κ·ΈλΌμš΄λ“œμ—μ„œ μ‹€ν–‰ν•©λ‹ˆλ‹€.
  • StateManager μƒμ„±μžμ˜ νŒŒλΌλ―Έν„°λ‘œ μŠ€λ ˆλ“œ μ΅œλŒ€ 개수λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

였λ₯˜ μ²˜λ¦¬μ™€ μž¬μ‹œλ„

  • μ‹€νŒ¨ μ½œλ°±μ—μ„œ λ‘œκΉ…/μ•Œλ¦Ό/보정 λ‘œμ§μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • nextEventRetryCount와 RetryManagerλ₯Ό 톡해 반볡 μ‹€ν–‰ μ „λž΅μ„ μ„€κ³„ν•˜μ„Έμš”.

예제: ATM 데λͺ¨

ν…ŒμŠ€νŠΈ μ½”λ“œμ— ATM μƒνƒœ λ¨Έμ‹  μ˜ˆμ œκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

  • 경둜: JFSM/src/test/java/atm
  • UML: JFSM/src/test/java/atm/uml/atm_state.puml

μ‹€ν–‰ 팁:

# Maven ν…ŒμŠ€νŠΈ μ‹€ν–‰
mvn -f JFSM/pom.xml test -Dtest=atm.BasicAtmStateTest

ν…ŒμŠ€νŠΈ μ‹€ν–‰

# 전체 ν…ŒμŠ€νŠΈ
mvn -f JFSM/pom.xml test

# νŠΉμ • ν…ŒμŠ€νŠΈ 클래슀
mvn -f JFSM/pom.xml -Dtest=TestMain test

Maven/λΉŒλ“œ

ν”„λ‘œμ νŠΈλŠ” Maven κΈ°λ°˜μž…λ‹ˆλ‹€. 둜컬 λͺ¨λ“ˆλ‘œ μ‚¬μš©ν•  경우 StateManager λ“± APIλ₯Ό 직접 import ν•˜μ—¬ μ‚¬μš©ν•˜μ„Έμš”. (λ³„λ„μ˜ 쀑앙 μ €μž₯μ†Œ 배포 정보가 μ—†λ‹€λ©΄ μ†ŒμŠ€ 의쑴 λ˜λŠ” 둜컬 μ„€μΉ˜λ₯Ό μ΄μš©ν•˜μ„Έμš”.)

# λΉŒλ“œ
mvn -f JFSM/pom.xml clean package

# 둜컬 μ„€μΉ˜ (λ‹€λ₯Έ ν”„λ‘œμ νŠΈμ—μ„œ μ‚¬μš©)
mvn -f JFSM/pom.xml clean install

의쑴 μ˜ˆμ‹œ(pom.xml) β€” 둜컬 μ„€μΉ˜ ν›„ μ‚¬μš© μ‹œ:

<dependency>
  <groupId>com.fsm</groupId>
  <artifactId>JFSM</artifactId>
  <version>1.0.0</version>
</dependency>

FAQ

  • Q. μƒνƒœ μ²œμ΄λŠ” μ–΄λ””μ„œ μ •μ˜ν•˜λ‚˜μš”?
    • A. StateHandler.addState(...)λ₯Ό 톡해 μ •μ˜ν•©λ‹ˆλ‹€.
  • Q. μ—¬λŸ¬ from μƒνƒœμ—μ„œ 같은 이벀트둜 천이 κ°€λŠ₯ν• κΉŒμš”?
    • A. κ°€λŠ₯ν•©λ‹ˆλ‹€. HashSet<String>으둜 from μƒνƒœ 집합을 λ„˜κΈ°λ©΄ λ©λ‹ˆλ‹€.
  • Q. λ‹€μŒ 이벀트λ₯Ό μžλ™ μ‹€ν–‰ν•˜κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.
    • A. nextEvent와 delayλ₯Ό μ§€μ •ν•˜μ„Έμš”. μ‹€νŒ¨ μ‹œ nextEventRetryCount둜 μž¬μ‹œλ„ 횟수λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.
  • Q. μŠ€λ ˆλ“œ κ°œμˆ˜λŠ” μ–΄λ–»κ²Œ μ‘°μ ˆν•˜λ‚˜μš”?
    • A. new StateManager(threadMaxCount)둜 생성 μ‹œ μ„€μ •ν•©λ‹ˆλ‹€.

λΌμ΄μ„ μŠ€

이 ν”„λ‘œμ νŠΈλŠ” LICENSE 파일의 λ‚΄μš©μ„ λ”°λ¦…λ‹ˆλ‹€.

About

FSM Manager

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages