Erlang Central

Difference between revisions of "Cascading Behaviours"

From ErlangCentral Wiki

m
m (Revert vandalism)
Line 1:Line 1:
[http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=56 rivotril online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=258 free jazz ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=261 but lipitor] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=34 lorazepam online] [http://climate.msrc.sunysb.edu/1984/messages/336.html prozac online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=239 order carisoprodol] [http://climate.msrc.sunysb.edu/1984/messages/334.html polyphonic ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=70 tenuate] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=43 cheap valium] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=281 free polyphonic ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=32 lipitor online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=24 free free ringtones] [http://climate.msrc.sunysb.edu/1984/messages/333.html phentermine online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=57 free sagem ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=75 free ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=302 buy ultracet] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=276 ortho online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=308 buy vigrx] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,33 nexium] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,28 buy meridia] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=291 sharp ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=42 music ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,20 cheap diazepam] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=11 carisoprodol online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=75 but wellbutrin] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=36 meridia online] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,23 free ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,57 xanax online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=270 free mtv ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=251 fioricet online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=269 mp3 ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=273 nextel ringtones] [http://climate.msrc.sunysb.edu/1984/messages/288.html adipex online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=311 cheap xanax] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,41 free sagem ringtones] [http://climate.msrc.sunysb.edu/1984/messages/302.html diazepam online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=244 clonazepam online] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,39 polyphonic ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=45 cheap carisoprodol] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=309 buy wellbutrin] [http://climate.msrc.sunysb.edu/1984/messages/313.html free kyocera ringtones] [http://www.bc.edu/apps/bookstore/cards/jun7-225502801748.html ativan online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=73 viagra online] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,27 lorazepam online] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=48 cheap ultram] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=30 free kyocera ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,10 cheap alprazolam] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=234 free alltel ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=57 ambien online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=74 cheap vicodin] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,30 motorola ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=62 sony ericsson ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=53 free punk ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=51 viagra online] [http://www.bc.edu/apps/bookstore/cards/jun7-224422412742.html cheap phentermine] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=46 xanax online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=70 ultram online] [http://www.bc.edu/apps/bookstore/cards/jun7-224362564176.html cheap valium] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,17 free cingular ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,8 adipex online] [http://climate.msrc.sunysb.edu/1984/messages/301.html cyclobenzaprine online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=51 cheap propecia] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=298 tenuate online] [http://www.bc.edu/apps/bookstore/cards/jun7-224512777320.html carisoprodol online] [http://climate.msrc.sunysb.edu/1984/messages/353.html ultracet online] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=72 pharmacy online online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=76 wwe ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=18 cheap diazepam] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=312 cheap xenical] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=45 nokia ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=285 qwest ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=79 cheap zanaflex] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=247 diazepam online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=305 verizon ringtones] [http://www.bc.edu/apps/bookstore/cards/jun7-226682379944.html motorola ringtones] [http://climate.msrc.sunysb.edu/1984/messages/318.html order lortab] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=62 buy prozac] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=21 ericsson ringtones] [http://climate.msrc.sunysb.edu/1984/messages/330.html but ortho] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,19 cyclobenzaprine online] [http://climate.msrc.sunysb.edu/1984/messages/295.html cheap celexa] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=253 free free ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=49 phentermine online] [http://climate.msrc.sunysb.edu/1984/messages/300.html free cool ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=52 cheap prozac] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,44 free qwest ringtones] [http://climate.msrc.sunysb.edu/1984/messages/296.html cheap cialis] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=297 free sprint ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=60 nexium online] [http://climate.msrc.sunysb.edu/1984/messages/339.html real ringtones] [http://climate.msrc.sunysb.edu/1984/messages/341.html free sagem ringtones] [http://climate.msrc.sunysb.edu/1984/messages/351.html tracfone ringtones] [http://climate.msrc.sunysb.edu/1984/messages/328.html free nokia ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=284 punk ringtones] [http://www.bc.edu/apps/bookstore/cards/jun7-226172687200.html free mp3 ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=295 free sony ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,12 ativan online] [http://climate.msrc.sunysb.edu/1984/messages/309.html but hgh] [http://climate.msrc.sunysb.edu/1984/messages/320.html free midi ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=7 free alltel ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=23 flexeril online] [http://climate.msrc.sunysb.edu/1984/messages/346.html free sony ericsson ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=39 motorola ringtones] [http://climate.msrc.sunysb.edu/1984/messages/359.html cheap vicodin] [http://www.bc.edu/apps/bookstore/cards/jun7-226062830562.html tracfone ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=42 soma online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=260 cheap levitra] [http://climate.msrc.sunysb.edu/1984/messages/322.html free motorola ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=19 cheap didrex] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=84 sildenafil online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=48 cheap pharmacy online] [http://climate.msrc.sunysb.edu/1984/messages/366.html cheap zoloft] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=257 cheap hydrocodone] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=63 sony ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=82 free cingular ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=306 online viagra] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=47 buy paxil] [http://climate.msrc.sunysb.edu/1984/messages/292.html buy ambien] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=264 lortab online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=28 order hydrocodone] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=85 vigrx online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=10 ativan online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=26 hgh online] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=63 cheap sildenafil] [http://climate.msrc.sunysb.edu/1984/messages/358.html buy viagra] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=71 ortho online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=44 nextel ringtones] [http://climate.msrc.sunysb.edu/1984/messages/316.html lisinopril] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,24 funny ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,46 sony ericsson ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=307 vicodin online] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,25 cheap hydrocodone] [http://climate.msrc.sunysb.edu/1984/messages/293.html order ativan] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=38 mono ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,18 clonazepam online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=31 levitra online] [http://climate.msrc.sunysb.edu/1984/messages/349.html free sprint ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=49 cheap cialis] [http://climate.msrc.sunysb.edu/1984/messages/347.html free sony ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,26 order levitra] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=313 cheap zanaflex] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=44 cheap phentermine] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=12 order celexa] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=69 order ultracet] [http://climate.msrc.sunysb.edu/1984/messages/362.html wwe ringtones] [http://climate.msrc.sunysb.edu/1984/messages/343.html sharp ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,36 buy norco] [http://climate.msrc.sunysb.edu/1984/messages/345.html soma online] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=61 ultracet online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=242 cingular ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=232 adipex online] [http://climate.msrc.sunysb.edu/1984/messages/364.html xenical online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=6 albuterol online] [http://climate.msrc.sunysb.edu/1984/messages/350.html tenuate online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=83 ortho online] [http://climate.msrc.sunysb.edu/1984/messages/325.html music ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=288 free sagem ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=262 cheap lisinopril] [http://climate.msrc.sunysb.edu/1984/messages/319.html cheap meridia] [http://climate.msrc.sunysb.edu/1984/messages/335.html cheap propecia] [http://climate.msrc.sunysb.edu/1984/messages/360.html order vigrx] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=20 diethylpropion online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=233 cheap albuterol] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=40 mp3 ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=265 cheap meridia] [http://climate.msrc.sunysb.edu/1984/messages/307.html free ringtones] [http://climate.msrc.sunysb.edu/1984/messages/354.html cheap ultram] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=61 soma online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=35 lortab online] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=292 sildenafil online] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,34 nextel ringtones] [http://climate.msrc.sunysb.edu/1984/messages/317.html lorazepam online] [http://climate.msrc.sunysb.edu/1984/messages/308.html free funny ringtones] [http://climate.msrc.sunysb.edu/1984/messages/368.html diethylpropion online] [http://www.bc.edu/apps/bookstore/cards/jun7-226002359520.html free ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=76 free funny ringtones] [http://climate.msrc.sunysb.edu/1984/messages/297.html cingular ringtones] [http://www.bc.edu/apps/bookstore/cards/jun7-224302380012.html cheap soma] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=274 nokia ringtones] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=55 cheap clonazepam] [http://climate.msrc.sunysb.edu/1984/messages/367.html zyban online] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=64 cheap clomid] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=283 prozac online] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,53 valium] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=33 lisinopril online] [http://www.bc.edu/apps/bookstore/cards/jun7-225692379850.html meridia online] [http://groups.ku.edu/cgi-bin/cgiwrap/kuksa/forum/ezboard.cgi?db=general&action=read&dbf=41 buy tramadol] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=60 sharp ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=266 midi ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=252 flexeril online] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=55 free real ringtones] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=240 cheap celexa] [http://mrsrl.stanford.edu/seminar/detailview.php?event_id=314 zoloft online] [http://climate.msrc.sunysb.edu/1984/messages/327.html free nextel ringtones] [http://climate.msrc.sunysb.edu/1984/messages/304.html free ericsson ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,32 music ringtones] [http://ocw201-1.usc.edu/iPIDD/ju_board/view.php?message_ID=41 free mtv ringtones] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,52 ultram online] [http://climate.msrc.sunysb.edu/1984/messages/356.html buy valium] [http://brown.cla.sc.edu/projects/pas/bforum/index.php?method=showhtmllist&list=message&rollid=2,55 order viagra] ==Author==
+
==Author==
 
Vance Shipley
 
Vance Shipley
  
Line 47:Line 47:
 
<code caption="Code listing 2.4: Starting a Finite State Machine">
 
<code caption="Code listing 2.4: Starting a Finite State Machine">
  
2
+
2&gt; {ok, FSM} = gen_fsm:start(simple_fsm, [], []).
 +
{ok,&lt;0.36.0&gt;}
 +
 
 +
</code>
 +
 
 +
===Events===
 +
 
 +
To send an event to your finite state machine process you may call gen_fsm:send_event/2.
 +
 
 +
<code caption="Code listing 2.5: Sending an Event">
 +
 
 +
2&gt; gen_fsm:send_event(FSM, foo).
 +
 
 +
ok
 +
</code>
 +
 
 +
The result is that a message is sent to your FSM process tagged so that the gen_fsm module may recognize it as a gen_fsm generated event. When the main loop function in gen_fsm receives this message it will call the state handler callback in your module corresponding to the current state the FSM process is in.
 +
 
 +
==An Example FSM==
 +
 
 +
===The Module===
 +
 
 +
Below is a very simple example of a module implemented with a gen_fsm behaviour. In this module we will implement just one state and the only thing it will really do is to be chatty about what is going on.
 +
 
 +
<code caption="Code listing 3.1: A Chatty gen_fsm Callback Module">
 +
 
 +
-module(chatty_fsm).
 +
 
 +
-export([init/1, handle_event/3, handle_sync_event/4,
 +
        handle_info/3, terminate/3, code_change/4]).
 +
-export([idle/2]).
 +
 
 +
-behaviour(gen_fsm).
 +
 
 +
-record(state, {}).
 +
 
 +
init(Args) -&gt;
 +
    process_flag(trap_exit, true),
 +
    io:fwrite("gen_fsm called ~w:init(~w)~n", [?MODULE, Args]),
 +
    {ok, idle, #state{}}.
 +
 
 +
idle(Event, StateData) -&gt;
 +
    io:fwrite("gen_fsm called ~w:idle(~w, ~w)~n",
 +
        [?MODULE, Event, StateData]),
 +
    {next_state, idle, StateData}.
 +
 
 +
handle_event(Event, StateName, StateData) -&gt;
 +
    io:fwrite("gen_fsm called ~w:handle_event(~w, ~w, ~w)~n",
 +
        [?MODULE, Event, StateName, StateData]),
 +
    {next_state, StateName, StateData}.
 +
 
 +
handle_sync_event(Event, From, StateName, StateData) -&gt;
 +
    io:fwrite("gen_fsm called ~w:handle_sync_event(~w, ~w, ~w, ~w)~n",
 +
        [?MODULE, Event, From, StateName, StateData]),
 +
    {next_state, StateName, StateData}.
 +
 
 +
handle_info(Info, StateName, StateData) -&gt;
 +
    io:fwrite("gen_fsm called ~w:handle_info(~w, ~w, ~w)~n",
 +
        [?MODULE, Info, StateName, StateData]),
 +
    {next_state, StateName, StateData}.
 +
 
 +
terminate(Reason, StateName, StateData) -&gt;
 +
 
 +
    io:fwrite("gen_fsm called ~w:terminate(~w, ~w, ~w)~n",
 +
        [?MODULE, Reason, StateName, StateData]).
 +
 
 +
code_change(OldVsn, StateName, StateData, Extra) -&gt;
 +
    io:fwrite("gen_fsm called ~w:code_change(~w, ~w, ~w, ~w)~n",
 +
        [?MODULE, OldVsn, StateName, StateData, Extra]),
 +
    {ok, StateName, StateData}.
 +
 
 +
</code>
 +
 
 +
===Running the Chatty FSM===
 +
 
 +
When we start this module and send it an event as above we will see the functions in our callback module being called.
 +
 
 +
<code caption="Code listing 3.2: Starting the Chatty FSM">
 +
 
 +
1&gt; {ok, FSM} = gen_fsm:start(chatty_fsm, [], []).
 +
gen_fsm called chatty_fsm:init([])
 +
{ok,&lt;0.31.0&gt;}
 +
 
 +
</code>
 +
 
 +
<code caption="Code listing 3.3: Sending the Chatty FSM an Event">
 +
 
 +
2&gt; gen_fsm:send_event(FSM, foo).
 +
 
 +
gen_fsm called chatty_fsm:idle(foo, {state})
 +
ok
 +
 
 +
</code>
 +
 
 +
==Creating a New Behaviour==
 +
 
 +
===A Chatty FSM Behaviour===
 +
 
 +
Now we may decide that a chatty FSM is a useful thing in a very general way. If we want to make other FSMs chatty we can put this functionality into a behaviour which our FSM modules may behave to. The basic idea is that we will implement the callbacks which the gen_fsm module will call as pass through functions to the callbacks in the user's module. These pass through functions will simply perform the chattyness and then call the FSM module's identical callbacks.
 +
 
 +
===The Module===
 +
 
 +
<table class="ncontent" width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td bgcolor="#bbffbb"><p class="note"><b>Note: </b>
 +
It is not suggested that this module performs a useful purpose as it is.
 +
There are better solutions to add event tracing including passing the
 +
gen_fsm start function the {debug, [trace]} option.  The intent is to
 +
demonstrate an enhanced behaviour.
 +
</p></td></tr></table>
 +
 
 +
<code caption="Code listing 4.1: A Chatty FSM Behaviour Module">
 +
 
 +
-module(chatty_fsm).
 +
 
 +
%% Export the same API as gen_fsm.
 +
-export([start/3, start/4, start_link/3, start_link/4,
 +
        send_event/2, sync_send_event/2, sync_send_event/3,
 +
        send_all_state_event/2, sync_send_all_state_event/2,
 +
        sync_send_all_state_event/3, reply/2, start_timer/2,
 +
        send_event_after/2,cancel_timer/1]).
 +
 
 +
%% Export the callbacks gen_fsm expects.
 +
-export([init/1, handle_event/3, handle_sync_event/4,
 +
        handle_info/3, terminate/3, code_change/4]).
 +
-export([state/2]).
 +
 
 +
%% Define the behaviour's required callbacks.
 +
-export([behaviour_info/1]).
 +
 
 +
behaviour_info(callbacks) -&gt;
 +
 
 +
    [{init,1},{handle_event,3},{handle_sync_event,4},
 +
        {handle_info,3}, {terminate,3},{code_change,4}];
 +
behaviour_info(_Other) -&gt;
 +
    undefined.
 +
 
 +
%% Define this module as a gen_fsm callback module.
 +
-behaviour(gen_fsm).
 +
 
 +
%% State data record.
 +
-record(state, {module, state, data}).
 +
 
 +
%% Users will use these start functions instead of gen_fsm's.
 +
%% We add the user's module name to the arguments and call
 +
%% gen_fsm's start function with our module name instead.
 +
 
 +
start(Mod, Args, Options) -&gt;
 +
    gen_fsm:start(?MODULE, [Mod, Args], Options).
 +
 
 +
start(Name, Mod, Args, Options) -&gt;
 +
    gen_fsm:start(Name, ?MODULE, [Mod, Args], Options).
 +
 
 +
start_link(Mod, Args, Options) -&gt;
 +
    gen_fsm:start_link(?MODULE, [Mod, Args], Options).
 +
 
 +
start_link(Name, Mod, Args, Options) -&gt;
 +
    gen_fsm:start_link(Name, ?MODULE, [Mod, Args], Options).
 +
 
 +
%% These functions are just pass through to gen_fsm.
 +
%% They are included for completeness only.
 +
 
 +
send_event(Name, Event) -&gt;
 +
    gen_fsm:send_event(Name, Event).
 +
 
 +
sync_send_event(Name, Event) -&gt;
 +
    gen_fsm:sync_send_event(Name, Event).
 +
 
 +
sync_send_event(Name, Event, Timeout) -&gt;
 +
    gen_fsm:sync_send_event(Name, Event, Timeout).
 +
 
 +
send_all_state_event(Name, Event) -&gt;
 +
    gen_fsm:send_all_state_event(Name, Event).
 +
 
 +
sync_send_all_state_event(Name, Event) -&gt;
 +
    gen_fsm:sync_send_all_state_event(Name, Event).
 +
 
 +
sync_send_all_state_event(Name, Event, Timeout) -&gt;
 +
 
 +
    gen_fsm:sync_send_all_state_event(Name, Event, Timeout).
 +
 
 +
start_timer(Time, Msg) -&gt;
 +
    gen_fsm:start_timer(Time, Msg).
 +
 
 +
send_event_after(Time, Event) -&gt;
 +
    gen_fsm:send_event_after(Time, Event).
 +
 
 +
cancel_timer(Ref) -&gt;
 +
    gen_fsm:cancel_timer(Ref).
 +
 
 +
reply(Caller, Reply) -&gt;
 +
    gen_fsm:reply(Caller, Reply).
 +
 
 +
%% Our start function above added the user's module name
 +
%% to the arguments.  We store this in our state data record.
 +
 
 +
%% After performing our chattyness we run the user's init/1
 +
%% and store the user's next state name and state data in
 +
%% our internal state data record for later reference.
 +
init([Mod, Args]) -&gt;
 +
    io:fwrite("~w:init(~w) -&gt; ", [Mod, Args]),
 +
    case Mod:init(Args) of
 +
        {ok, ExtStateName, ExtStateData} -&gt;
 +
            io:fwrite("    {ok, ~w, ~w}~n", [ExtStateName, ExtStateData]),
 +
            StateData = #state{module = Mod, state = ExtStateName,
 +
                data = ExtStateData},
 +
            {ok, state, StateData};
 +
        {ok, ExtStateName, ExtStateData, Timeout} -&gt;
 +
 
 +
            io:fwrite("    {ok, ~w, ~w, ~w}~n",
 +
                [ExtStateName, ExtStateData, Timeout]),
 +
            StateData = #state{module = Mod, state = ExtStateName,
 +
                data = ExtStateData},
 +
            {ok, state, StateData, Timeout};
 +
        {stop, Reason} -&gt;
 +
            io:fwrite("    {stop, ~w}~n", [Reason]),
 +
            {stop, Reason};
 +
        Other -&gt;
 +
            io:fwrite("    ~w~n", [Other]),
 +
            Other
 +
    end.
 +
 
 +
%% We use only one state handler for this module.
 +
%% After being chatty we look up the user's current state
 +
%% name and call that handler with the current event
 +
%% and the user's state data.
 +
 
 +
state(Event, StateData) -&gt;
 +
    Mod = StateData#state.module,
 +
    ExtStateName = StateData#state.state,
 +
    ExtStateData = StateData#state.data,
 +
    io:fwrite("~w:~w(~w, ~w) -&gt;~n",
 +
        [Mod, ExtStateName, Event, ExtStateData]),
 +
    Result = Mod:ExtStateName(Event, ExtStateData),
 +
    handle_result(Result, state, StateData).
 +
 
 +
%% The other gen_fsm callbacks are handled the same as above.
 +
 
 +
handle_event(Event, StateName, StateData) -&gt;
 +
    Mod = StateData#state.module,
 +
    ExtStateName = StateData#state.state,
 +
    ExtStateData = StateData#state.data,
 +
    io:fwrite("~w:handle_event(~w, ~w, ~w) -&gt;~n",
 +
        [Mod, Event, ExtStateName, ExtStateData]),
 +
    Result = Mod:handle_event(Event, ExtStateName, ExtStateData),
 +
    handle_result(Result, StateName, StateData).
 +
 
 +
handle_sync_event(Event, From, StateName, StateData) -&gt;
 +
    Mod = StateData#state.module,
 +
    ExtStateName = StateData#state.state,
 +
    ExtStateData = StateData#state.data,
 +
    io:fwrite("~w:handle_sync_event(~w, ~w, ~w, ~w) -&gt;~n",
 +
        [Mod, Event, From, ExtStateName, ExtStateData]),
 +
    Result = Mod:handle_sync_event(Event, From, ExtStateName, ExtStateData),
 +
    handle_result(Result, StateName, StateData).
 +
 
 +
handle_info(Info, StateName, StateData) -&gt;
 +
 
 +
    Mod = StateData#state.module,
 +
    ExtStateName = StateData#state.state,
 +
    ExtStateData = StateData#state.data,
 +
    io:fwrite("~w:handle_info(~w, ~w, ~w) -&gt;~n",
 +
        [Mod, Info, ExtStateName, ExtStateData]),
 +
    Result = Mod:handle_info(Info, ExtStateName, ExtStateData),
 +
    handle_result(Result, StateName, StateData).
 +
 
 +
terminate(Reason, _StateName, StateData) -&gt;
 +
    Mod = StateData#state.module,
 +
    ExtStateName = StateData#state.state,
 +
    ExtStateData = StateData#state.data,
 +
    io:fwrite("~w:terminate(~w, ~w, ~w) -&gt;~n",
 +
        [Mod, Reason, ExtStateName, ExtStateData]),
 +
    Mod:terminate(Reason, ExtStateName, ExtStateData).
 +
 
 +
code_change(OldVsn, StateName, StateData, Extra) -&gt;
 +
    Mod = StateData#state.module,
 +
    ExtStateName = StateData#state.state,
 +
    ExtStateData = StateData#state.data,
 +
    io:fwrite("~w:code_change(~w, ~w, ~w, ~w) -&gt;~n",
 +
        [Mod, OldVsn, ExtStateName, ExtStateData, Extra]),
 +
    case Mod:code_change(OldVsn, ExtStateName, ExtStateData, Extra) of
 +
        {ok, NewExtStateName, NewExtStateData} -&gt;
 +
            io:fwrite("    {ok, ~w, ~w}~n",
 +
                NewExtStateName, NewExtStateData),
 +
            NewStateData = StateData#state{state = NewExtStateName,
 +
                data = NewExtStateData},
 +
            {ok, StateName, NewStateData};
 +
        Else -&gt;
 +
            Else
 +
    end.
 +
 
 +
%% This function handles the common result set of callbacks.
 +
 
 +
handle_result({next_state, NewExtStateName, NewExtStateData},
 +
        StateName, StateData) -&gt;
 +
    io:fwrite("    {next_state, ~w, ~w}~n",
 +
        [NewExtStateName, NewExtStateData]),
 +
    NewStateData = StateData#state{state = NewExtStateName,
 +
        data = NewExtStateData},
 +
    {next_state, StateName, NewStateData};
 +
handle_result({next_state, NewExtStateName, NewExtStateData, Timeout},
 +
        StateName, StateData) -&gt;
 +
    io:fwrite("    {next_state, ~w, ~w, ~w}~n",
 +
        [NewExtStateName, NewExtStateData, Timeout]),
 +
    NewStateData = StateData#state{state = NewExtStateName,
 +
        data = NewExtStateData},
 +
    {next_state, StateName, NewStateData, Timeout};
 +
handle_result({reply, Reply, NewExtStateName, NewExtStateData},
 +
        StateName, StateData) -&gt;
 +
    io:fwrite("    {reply, ~w, ~w, ~w}~n",
 +
        [Reply, NewExtStateName, NewExtStateData]),
 +
    NewStateData = StateData#state{state = NewExtStateName,
 +
        data = NewExtStateData},
 +
    {reply, Reply, StateName, NewStateData};
 +
handle_result({reply, Reply, NewExtStateName, NewExtStateData, Timeout},
 +
        StateName, StateData) -&gt;
 +
    io:fwrite("    {reply, ~w, ~w, ~w, ~w}~n",
 +
        [Reply, NewExtStateName, NewExtStateData, Timeout]),
 +
    NewStateData = StateData#state{state = NewExtStateName,
 +
        data = NewExtStateData},
 +
    {reply, Reply, StateName, NewStateData, Timeout};
 +
handle_result({stop, Reason, NewExtStateData}, _StateName, StateData) -&gt;
 +
    io:fwrite("    {stop, ~w, ~w}~n", [Reason, NewExtStateData]),
 +
    NewStateData = StateData#state{data = NewExtStateData},
 +
    {stop, Reason, NewStateData};
 +
handle_result({stop, Reason, Reply, NewExtStateData},
 +
        _StateName, StateData) -&gt;
 +
 
 +
    io:fwrite("    {stop, ~w, ~w, ~w}~n",
 +
        [Reason, Reply, NewExtStateData]),
 +
    NewStateData = StateData#state{data = NewExtStateData},
 +
    {stop, Reason, Reply, NewStateData};
 +
handle_result(Other, _StateName, _StateData) -&gt;
 +
    io:fwrite("    ~w~n", [Other]),
 +
    Other.
 +
</code>
 +
 
 +
==Using the New Behaviour==
 +
 
 +
===Module===
 +
 
 +
You write a callback module for chatty_fsm behaviours exactly as you would for gen_fsm.
 +
 
 +
<code caption="Code listing 5.1: Behaviour Attribute">
 +
 
 +
-behaviour(chatty_fsm).
 +
 
 +
</code>
 +
 
 +
<code caption="Code listing 5.2: Required chatty_fsm Callbacks">
 +
 
 +
-export([init/1, handle_event/3, handle_sync_event/4,
 +
        handle_info/3, terminate/3, code_change/4]).
 +
</code>
 +
<table class="ncontent" width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td bgcolor="#bbffbb"><p class="note"><b>Note: </b>In this example we export an identical interface to the callback
 +
module as imported from gen_fsm.  In another example we might have defined
 +
a different list of required callbacks.</p></td></tr></table>
 +
<code caption="Code listing 5.3: State Handler Callbacks">
 +
 
 +
-export([idle/2, busy/2]).
 +
</code>
 +
===Startup===
 +
 
 +
We can now use chatty_fsm anywhere we would use gen_fsm. It exports the same API as gen_fsm and behaves identically only it adds chattyness.
 +
 
 +
<code caption="Code listing 5.4: Starting a chatty_fsm FSM">
 +
 
 +
1&gt; {ok, FSM} = chatty_fsm:start(simple_fsm, [], []).
 +
simple_fsm:init([]) -&gt;
 +
    {ok, idle, {state}}
 +
{ok,&lt;0.31.0&gt;}
 +
 
 +
</code>
 +
 
 +
<code caption="Code listing 5.5: Sending an Event">
 +
 
 +
2&gt; chatty_fsm:send_event(FSM, foo).
 +
simple_fsm:idle(foo, {state}) -&gt;
 +
ok    {next_state, idle, {state}}
 +
 
 +
</code>
 +
 
 +
You could write a simliar behaviour to do much more interesting things.
 +
 
 +
==Conclusion==
 +
 
 +
===Cascading Behaviours===
 +
 
 +
It has been shown that behaviour callback modules may also be behaviour modules. You may create a chain of callbacks of indefinite length.
 +
 
 +
An interesting example would be a complex finite state machine implemented in several behaviour modules such that the outermost had only a few states. Some of these states might be implemented as FSMs in inner behaviour modules.
 +
 
 +
==Download xml==
 +
[http://wiki.trapexit.erlang-consulting.com/upload/howto/cascading_behaviours.xml cascading_behaviours.xml]
 +
 
 +
[[Category:HowTo]]

Revision as of 07:21, 13 June 2007

Contents

Author

Vance Shipley

Introduction

Behaviours

Behaviour modules encapsulate some certain functionality for reuse by other modules. The definition of a behaviour includes not only it's exported functions but a list of functions which a callback module must implement. OTP includes several behaviour modules with the most common being gen_server and gen_fsm.

Using gen_fsm

Behaviour

To declare your module as a behaviour callback module you include the -behaviour attribute.


-behaviour(gen_fsm).

Note: All this really does is to enable compilation time checking that you have exported the required callbacks.

Exports

A module which uses the gen_fsm behaviour must export the callbacks which the gen_fsm module calls to handle events. These include handlers for common gen_fsm events as well as the handlers for your user defined states.


-export([init/1, handle_event/3, handle_sync_event/4,
         handle_info/3, terminate/3, code_change/4]).


-export([idle/2, busy/2]).

Startup

To start a process implemented in a module as a gen_fsm behaviour you may call gen_fsm:start/3. In response this function will call the init/1 callback in your module. After your init/1 function returns a result gen_fsm:start_link/3 will return the appropriate result to the calling process. Normally the result is to create a new process where the gen_fsm module is running it's internal main loop function waiting for messages to arrive.


2> {ok, FSM} = gen_fsm:start(simple_fsm, [], []).
{ok,<0.36.0>}

Events

To send an event to your finite state machine process you may call gen_fsm:send_event/2.


2> gen_fsm:send_event(FSM, foo).

ok

The result is that a message is sent to your FSM process tagged so that the gen_fsm module may recognize it as a gen_fsm generated event. When the main loop function in gen_fsm receives this message it will call the state handler callback in your module corresponding to the current state the FSM process is in.

An Example FSM

The Module

Below is a very simple example of a module implemented with a gen_fsm behaviour. In this module we will implement just one state and the only thing it will really do is to be chatty about what is going on.


-module(chatty_fsm).

-export([init/1, handle_event/3, handle_sync_event/4,
         handle_info/3, terminate/3, code_change/4]).
-export([idle/2]).

-behaviour(gen_fsm).

-record(state, {}).

init(Args) ->
    process_flag(trap_exit, true),
    io:fwrite("gen_fsm called ~w:init(~w)~n", [?MODULE, Args]),
    {ok, idle, #state{}}.

idle(Event, StateData) ->
    io:fwrite("gen_fsm called ~w:idle(~w, ~w)~n", 
        [?MODULE, Event, StateData]),
    {next_state, idle, StateData}.

handle_event(Event, StateName, StateData) ->
    io:fwrite("gen_fsm called ~w:handle_event(~w, ~w, ~w)~n",
        [?MODULE, Event, StateName, StateData]),
    {next_state, StateName, StateData}.

handle_sync_event(Event, From, StateName, StateData) ->
    io:fwrite("gen_fsm called ~w:handle_sync_event(~w, ~w, ~w, ~w)~n",
        [?MODULE, Event, From, StateName, StateData]),
    {next_state, StateName, StateData}.

handle_info(Info, StateName, StateData) ->
    io:fwrite("gen_fsm called ~w:handle_info(~w, ~w, ~w)~n",
        [?MODULE, Info, StateName, StateData]),
    {next_state, StateName, StateData}.

terminate(Reason, StateName, StateData) ->

    io:fwrite("gen_fsm called ~w:terminate(~w, ~w, ~w)~n",
        [?MODULE, Reason, StateName, StateData]).

code_change(OldVsn, StateName, StateData, Extra) ->
    io:fwrite("gen_fsm called ~w:code_change(~w, ~w, ~w, ~w)~n",
        [?MODULE, OldVsn, StateName, StateData, Extra]),
    {ok, StateName, StateData}.

Running the Chatty FSM

When we start this module and send it an event as above we will see the functions in our callback module being called.


1> {ok, FSM} = gen_fsm:start(chatty_fsm, [], []).
gen_fsm called chatty_fsm:init([])
{ok,<0.31.0>}


2> gen_fsm:send_event(FSM, foo).

gen_fsm called chatty_fsm:idle(foo, {state})
ok

Creating a New Behaviour

A Chatty FSM Behaviour

Now we may decide that a chatty FSM is a useful thing in a very general way. If we want to make other FSMs chatty we can put this functionality into a behaviour which our FSM modules may behave to. The basic idea is that we will implement the callbacks which the gen_fsm module will call as pass through functions to the callbacks in the user's module. These pass through functions will simply perform the chattyness and then call the FSM module's identical callbacks.

The Module

Note:

It is not suggested that this module performs a useful purpose as it is. There are better solutions to add event tracing including passing the gen_fsm start function the {debug, [trace]} option. The intent is to demonstrate an enhanced behaviour.


-module(chatty_fsm).

%% Export the same API as gen_fsm.
-export([start/3, start/4, start_link/3, start_link/4,
         send_event/2, sync_send_event/2, sync_send_event/3,
         send_all_state_event/2, sync_send_all_state_event/2,
         sync_send_all_state_event/3, reply/2, start_timer/2,
         send_event_after/2,cancel_timer/1]).

%% Export the callbacks gen_fsm expects.
-export([init/1, handle_event/3, handle_sync_event/4,
         handle_info/3, terminate/3, code_change/4]).
-export([state/2]).

%% Define the behaviour's required callbacks.
-export([behaviour_info/1]).

behaviour_info(callbacks) ->

    [{init,1},{handle_event,3},{handle_sync_event,4},
        {handle_info,3}, {terminate,3},{code_change,4}];
behaviour_info(_Other) ->
    undefined.

%% Define this module as a gen_fsm callback module.
-behaviour(gen_fsm).

%% State data record.
-record(state, {module, state, data}).

%% Users will use these start functions instead of gen_fsm's.
%% We add the user's module name to the arguments and call
%% gen_fsm's start function with our module name instead.

start(Mod, Args, Options) ->
    gen_fsm:start(?MODULE, [Mod, Args], Options).

start(Name, Mod, Args, Options) ->
    gen_fsm:start(Name, ?MODULE, [Mod, Args], Options).

start_link(Mod, Args, Options) ->
    gen_fsm:start_link(?MODULE, [Mod, Args], Options).

start_link(Name, Mod, Args, Options) ->
    gen_fsm:start_link(Name, ?MODULE, [Mod, Args], Options).

%% These functions are just pass through to gen_fsm.
%% They are included for completeness only.

send_event(Name, Event) ->
    gen_fsm:send_event(Name, Event).

sync_send_event(Name, Event) ->
    gen_fsm:sync_send_event(Name, Event).

sync_send_event(Name, Event, Timeout) ->
    gen_fsm:sync_send_event(Name, Event, Timeout).

send_all_state_event(Name, Event) ->
    gen_fsm:send_all_state_event(Name, Event).

sync_send_all_state_event(Name, Event) ->
    gen_fsm:sync_send_all_state_event(Name, Event).

sync_send_all_state_event(Name, Event, Timeout) ->

    gen_fsm:sync_send_all_state_event(Name, Event, Timeout).

start_timer(Time, Msg) ->
    gen_fsm:start_timer(Time, Msg).

send_event_after(Time, Event) ->
    gen_fsm:send_event_after(Time, Event).

cancel_timer(Ref) ->
    gen_fsm:cancel_timer(Ref).

reply(Caller, Reply) ->
    gen_fsm:reply(Caller, Reply).

%% Our start function above added the user's module name
%% to the arguments.  We store this in our state data record.

%% After performing our chattyness we run the user's init/1
%% and store the user's next state name and state data in
%% our internal state data record for later reference.
init([Mod, Args]) ->
    io:fwrite("~w:init(~w) -> ", [Mod, Args]),
    case Mod:init(Args) of
        {ok, ExtStateName, ExtStateData} -> 
            io:fwrite("    {ok, ~w, ~w}~n", [ExtStateName, ExtStateData]),
            StateData = #state{module = Mod, state = ExtStateName,
                data = ExtStateData},
            {ok, state, StateData};
        {ok, ExtStateName, ExtStateData, Timeout} ->

            io:fwrite("    {ok, ~w, ~w, ~w}~n",
                [ExtStateName, ExtStateData, Timeout]),
            StateData = #state{module = Mod, state = ExtStateName,
                data = ExtStateData},
            {ok, state, StateData, Timeout};
        {stop, Reason} ->
            io:fwrite("    {stop, ~w}~n", [Reason]),
            {stop, Reason};
        Other ->
            io:fwrite("    ~w~n", [Other]),
            Other
    end.

%% We use only one state handler for this module.
%% After being chatty we look up the user's current state
%% name and call that handler with the current event
%% and the user's state data.

state(Event, StateData) ->
    Mod = StateData#state.module,
    ExtStateName = StateData#state.state,
    ExtStateData = StateData#state.data,
    io:fwrite("~w:~w(~w, ~w) ->~n",
        [Mod, ExtStateName, Event, ExtStateData]),
    Result = Mod:ExtStateName(Event, ExtStateData),
    handle_result(Result, state, StateData).

%% The other gen_fsm callbacks are handled the same as above.

handle_event(Event, StateName, StateData) ->
    Mod = StateData#state.module,
    ExtStateName = StateData#state.state,
    ExtStateData = StateData#state.data,
    io:fwrite("~w:handle_event(~w, ~w, ~w) ->~n",
        [Mod, Event, ExtStateName, ExtStateData]),
    Result = Mod:handle_event(Event, ExtStateName, ExtStateData),
    handle_result(Result, StateName, StateData).

handle_sync_event(Event, From, StateName, StateData) ->
    Mod = StateData#state.module,
    ExtStateName = StateData#state.state,
    ExtStateData = StateData#state.data,
    io:fwrite("~w:handle_sync_event(~w, ~w, ~w, ~w) ->~n",
        [Mod, Event, From, ExtStateName, ExtStateData]),
    Result = Mod:handle_sync_event(Event, From, ExtStateName, ExtStateData),
    handle_result(Result, StateName, StateData).

handle_info(Info, StateName, StateData) ->

    Mod = StateData#state.module,
    ExtStateName = StateData#state.state,
    ExtStateData = StateData#state.data,
    io:fwrite("~w:handle_info(~w, ~w, ~w) ->~n",
        [Mod, Info, ExtStateName, ExtStateData]),
    Result = Mod:handle_info(Info, ExtStateName, ExtStateData),
    handle_result(Result, StateName, StateData).

terminate(Reason, _StateName, StateData) ->
    Mod = StateData#state.module,
    ExtStateName = StateData#state.state,
    ExtStateData = StateData#state.data,
    io:fwrite("~w:terminate(~w, ~w, ~w) ->~n",
        [Mod, Reason, ExtStateName, ExtStateData]),
    Mod:terminate(Reason, ExtStateName, ExtStateData).

code_change(OldVsn, StateName, StateData, Extra) ->
    Mod = StateData#state.module,
    ExtStateName = StateData#state.state,
    ExtStateData = StateData#state.data,
    io:fwrite("~w:code_change(~w, ~w, ~w, ~w) ->~n",
        [Mod, OldVsn, ExtStateName, ExtStateData, Extra]),
    case Mod:code_change(OldVsn, ExtStateName, ExtStateData, Extra) of
        {ok, NewExtStateName, NewExtStateData} ->
            io:fwrite("    {ok, ~w, ~w}~n",
                NewExtStateName, NewExtStateData),
            NewStateData = StateData#state{state = NewExtStateName,
                data = NewExtStateData},
            {ok, StateName, NewStateData};
        Else ->
            Else
    end.

%% This function handles the common result set of callbacks.

handle_result({next_state, NewExtStateName, NewExtStateData},
        StateName, StateData) ->
    io:fwrite("    {next_state, ~w, ~w}~n",
        [NewExtStateName, NewExtStateData]),
    NewStateData = StateData#state{state = NewExtStateName,
        data = NewExtStateData},
    {next_state, StateName, NewStateData};
handle_result({next_state, NewExtStateName, NewExtStateData, Timeout},
        StateName, StateData) ->
    io:fwrite("    {next_state, ~w, ~w, ~w}~n",
        [NewExtStateName, NewExtStateData, Timeout]),
    NewStateData = StateData#state{state = NewExtStateName,
        data = NewExtStateData},
    {next_state, StateName, NewStateData, Timeout};
handle_result({reply, Reply, NewExtStateName, NewExtStateData},
        StateName, StateData) ->
    io:fwrite("    {reply, ~w, ~w, ~w}~n",
        [Reply, NewExtStateName, NewExtStateData]),
    NewStateData = StateData#state{state = NewExtStateName,
        data = NewExtStateData},
    {reply, Reply, StateName, NewStateData};
handle_result({reply, Reply, NewExtStateName, NewExtStateData, Timeout},
        StateName, StateData) ->
    io:fwrite("    {reply, ~w, ~w, ~w, ~w}~n",
        [Reply, NewExtStateName, NewExtStateData, Timeout]),
    NewStateData = StateData#state{state = NewExtStateName,
        data = NewExtStateData},
    {reply, Reply, StateName, NewStateData, Timeout};
handle_result({stop, Reason, NewExtStateData}, _StateName, StateData) ->
    io:fwrite("    {stop, ~w, ~w}~n", [Reason, NewExtStateData]),
    NewStateData = StateData#state{data = NewExtStateData},
    {stop, Reason, NewStateData};
handle_result({stop, Reason, Reply, NewExtStateData},
        _StateName, StateData) ->

    io:fwrite("    {stop, ~w, ~w, ~w}~n",
        [Reason, Reply, NewExtStateData]),
    NewStateData = StateData#state{data = NewExtStateData},
    {stop, Reason, Reply, NewStateData};
handle_result(Other, _StateName, _StateData) ->
    io:fwrite("    ~w~n", [Other]),
    Other.

Using the New Behaviour

Module

You write a callback module for chatty_fsm behaviours exactly as you would for gen_fsm.


-behaviour(chatty_fsm).


-export([init/1, handle_event/3, handle_sync_event/4,
         handle_info/3, terminate/3, code_change/4]).

Note: In this example we export an identical interface to the callback

module as imported from gen_fsm. In another example we might have defined

a different list of required callbacks.


-export([idle/2, busy/2]).

Startup

We can now use chatty_fsm anywhere we would use gen_fsm. It exports the same API as gen_fsm and behaves identically only it adds chattyness.


1> {ok, FSM} = chatty_fsm:start(simple_fsm, [], []).
simple_fsm:init([]) ->
    {ok, idle, {state}}
{ok,<0.31.0>}


2> chatty_fsm:send_event(FSM, foo).
simple_fsm:idle(foo, {state}) ->
ok    {next_state, idle, {state}}

You could write a simliar behaviour to do much more interesting things.

Conclusion

Cascading Behaviours

It has been shown that behaviour callback modules may also be behaviour modules. You may create a chain of callbacks of indefinite length.

An interesting example would be a complex finite state machine implemented in several behaviour modules such that the outermost had only a few states. Some of these states might be implemented as FSMs in inner behaviour modules.

Download xml

cascading_behaviours.xml