Skip to content

Samuel-Jeong/JFSM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

15 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

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

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages