extending standard behaviours

Vance Shipley <>
Wed Apr 17 02:31:29 CEST 2002


OK, I see how to do this now.  My new behaviour module will
look like a user to the gen_fsm behaviour and so it exports
the call backs that gen_fsm expects.  It will look like a
behaviour to it's users so we export the same but possibly
extended interface as gen_fsm to our users.  

I put this together and it seems to work brilliantly.  This
gives me exactly what I wanted which is to be able to write
generic handlers in one place and handle the specifics in
the individual state hanlder modules.  For instance when 
we terminate the fxs_fsm module's terminate/3 function will
do it's own clean up (hang up a call in a signaling specific
way) and then call the cha_fsm terminate function to do the
common clean up tasks (write to a log).  Messages received
by fxs_fsm which are not understood by it are forwarded on
to chan_fsm which handles them in a generic way.

Thanks Chris!

	-Vance


-----------------------------------------------------------------------------
-module(chan_fsm).
-behaviour(gen_fsm).

% export the gen_fsm interface
-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]).

% behaviour modules must export this function
-export([behaviour_info/1]).

% export the gen_fsm call backs
-export([init/1, handle_event/3, handle_sync_event/4,
		handle_info/3, terminate/3, code_change/4]).


%%
%% define what call backs users must export
%%
behaviour_info(callbacks) ->
	% we add our own requirements to those of gen_fsm
	[{idle, 2},{busy, 2}] ++ gen_fsm:behaviour_info(callbacks);
behaviour_info(Other) -> 
	gen_fsm:behaviour_info(Other).


%%
%% pass through functions to gen_fsm
%%

start(Mod, Args, Options) ->
	gen_fsm:start(Mod, Args, Options).

start(Name, Mod, Args, Options) ->
	gen_fsm:start(Name, Mod, Args, Options).

start_link(Mod, Args, Options) ->
    gen_fsm:start_link(Mod, Args, Options).

start_link(Name, Mod, Args, Options) ->
	gen_fsm:start_link(Mod, Args, Options).

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).

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).

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


%%
%% call backs
%%

init(Args) ->
	process_flag(trap_exit, true),
	io:fwrite("chan_fsm:  OK, let's play!~n"),
	{ok, idle, []}.
		
handle_event(Event, StateName, StateData) ->
	io:fwrite("chan_fsm:  Thank you for the ~w event.~n", [Event]),
	{next_state, StateName, StateData}.

handle_sync_event(Event, From, StateName, StateData) ->
	io:fwrite("chan_fsm:  I don't handle sync events!~n"),
	{reply, ignore, StateName, StateData}.
	
handle_info(Event, State, StateData) ->
	io:fwrite("chan_fsm:  Please use chan_fsm:send_event/2 to talk to me!~n"),
	{next_state, State, StateData}.

terminate(Reason, State, StateData) ->
	io:fwrite("chan_fsm:  It's been fun.  Bye.~n").

code_change(OldVersion, State, Data, Extra) ->
	io:fwrite("chan_fsm:  Nothing to do here.~n"),
	{ok, State, Data}.




-----------------------------------------------------------------------------
-module(fxs_fsm).
-behaviour(chan_fsm).

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

% export the gen_fsm call backs
-export([init/1, handle_event/3, handle_sync_event/4,
		handle_info/3, terminate/3, code_change/4]).


%%
%% states
%%

idle(Event, StateData) ->
	io:fwrite("The fxs state machine got ~w in ~w~n", [Event, idle]),
	{next_state, busy, StateData}.

busy(Event, StateData) ->
	io:fwrite("The fxs state machine got ~w in ~w~n", [Event, busy]),
	{next_state, idle, StateData}.


%%
%% call backs
%%

init(Args) ->
	chan_fsm:init(Args).

handle_event(Event, StateName, StateData) ->
	chan_fsm:handle_event(Event, StateName, StateData).

handle_sync_event(Event, From, StateName, StateData) ->
	chan_fsm:handle_sync_event(Event, From, StateName, StateData).
	
handle_info(foo, State, StateData) ->
	io:fwrite("The fxs state machine accepts your foo event~n"),
	{next_state, State, StateData};
handle_info(bar, State, StateData) ->
	io:fwrite("The fxs state machine accepts your bar event~n"),
	{next_state, State, StateData};
handle_info(Event, State, StateData) ->
	chan_fsm:handle_info(Event, State, StateData).

terminate(Reason, State, StateData) ->
	io:fwrite("Here I would do any fxs specific clean up.~n"),
	chan_fsm:terminate(Reason, State, StateData).

code_change(OldVersion, State, Data, Extra) ->
	io:fwrite("Here I would do any fxs specific code change tasks.~n"),
	chan_fsm:code_change(OldVersion, State, Data, Extra).




More information about the erlang-questions mailing list