From: Mikael K. <mik...@cr...> - 2008-04-06 21:18:04
|
Friday 04 April 2008 21:54:29 Steve Vinoski wrote: > Currently, yapps require mnesia by default for registration purpose. > For some systems, though, this might be considered overkill, and it > looks like the yapp code already allows for replacing the mnesia > implementation with something else via the yapp_registry_impl > application config parameter. > > Has anyone implemented such a replacement that uses a mechanism other > than mnesia? Any advice for writing such a replacement module? > > thanks, > --steve Hi Steve, it is fairly straightforward to replace the mnesia implementation with another one. The yapp_registry_impl environment entry in the yapp.app file should point to a module that implements the gen_server behaviour with three clauses in the handle_call/3 function: handle_call({yapp_registry, list}, _From, State) handle_call({yapp_registry, register,{SrvId,KeyValue}}, _From, State) handle_call({yapp_registry, unregister,{SrvId,Key}}, _From, State) as given by the "contract" in the yapp_registry.erl module. It should also take a Name parameter for its local name in the start_link/1 function. If the above makes no sense :-), I have included such a module that writes and reads the registry from an erlang consult file instead, which could give you a hint on how to implement your own. This module may take another (callback) module which only needs to implement two functions rget/0 and rput/1 to get the registry and to put the registry. May simplify things a bit, but introduces yet another level indirection. Best Regards Mikael %%-------------------------------------------------------------------- %% implements yapp_registry -module(yapp_my_registry_server). -behaviour(gen_server). %% API -export([start_link/1, start_link/2, rput/1, rget/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). %% registry module should export rput/1 and rget/0 -record(state, {registry_module}). %% API %%-------------------------------------------------------------------- %% Function: start_link() -> {ok,Pid} | ignore | {error,Error} %% Description: Starts the server %%-------------------------------------------------------------------- start_link(Name) -> start_link(Name, ?MODULE). %% Use own module as default registry_module start_link(Name, RegistryModule) -> gen_server:start_link({local, Name}, ?MODULE, [RegistryModule], []). -define(CSL_FILE,"my_registry_file.csl"). %% Registry is [{"serverid1",[{"/myurl1", myapp1},..]}, ..] %% Returns registry rget() -> case file:consult(?CSL_FILE) of {ok, Value} -> Value; _ -> %% Assume that no file exists, make an empty one rput([]), %% Will exit if file can't be created [] end. %% Puts Registry rput(Registry) -> unconsult(?CSL_FILE,Registry). unconsult(File, List) -> {ok,F} = file:open(File, write), [ io:format(F, "~p.~n",[X]) || X <- List ], file:close(F). %%===================================== %% gen_server callbacks %%===================================== %%-------------------------------------------------------------------- %% Function: init(Args) -> {ok, State} | %% {ok, State, Timeout} | %% ignore | %% {stop, Reason} %% Description: Initiates the server %%-------------------------------------------------------------------- init([Module]) -> {ok, #state{registry_module=Module}}. %%-------------------------------------------------------------------- %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} | %% {reply, Reply, State, Timeout} | %% {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, Reply, State} | %% {stop, Reason, State} %% Description: Handling call messages %%-------------------------------------------------------------------- handle_call({yapp_registry, list}, _From, #state{registry_module=M}=State) -> Reply = M:rget(), {reply, Reply, State}; handle_call({yapp_registry, register,{SrvId,KeyValue}}, _From, #state{registry_module=M}=State) -> NewRegistry = register_yapp(SrvId,KeyValue,M:rget()), Reply = M:rput(NewRegistry), {reply, Reply, State}; handle_call({yapp_registry, unregister,{SrvId,Key}}, _From, #state{registry_module=M}=State) -> NewRegistry = unregister_yapp(SrvId,Key, M:rget()), Reply = M:rput(NewRegistry), {reply, Reply, State}; handle_call({set_registry_module, Module}, _From, State) -> {reply, ok, State#state{registry_module=Module}}; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. %%-------------------------------------------------------------------- %% Function: handle_cast(Msg, State) -> {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} %% Description: Handling cast messages %%-------------------------------------------------------------------- handle_cast(_Msg, State) -> {noreply, State}. %%-------------------------------------------------------------------- %% Function: handle_info(Info, State) -> {noreply, State} | %% {noreply, State, Timeout} | %% {stop, Reason, State} %% Description: Handling all non call/cast messages %%-------------------------------------------------------------------- handle_info(_Info, State) -> {noreply, State}. %%-------------------------------------------------------------------- %% Function: terminate(Reason, State) -> void() %% Description: This function is called by a gen_server when it is about to %% terminate. It should be the opposite of Module:init/1 and do any necessary %% cleaning up. When it returns, the gen_server terminates with Reason. %% The return value is ignored. %%-------------------------------------------------------------------- terminate(_Reason, _State) -> ok. %%-------------------------------------------------------------------- %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState} %% Description: Convert process state when code is changed %%-------------------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- %% The yapp registry contains a list of {yapp_server_id, yapps} tuples, %% where yapps is a list of {UrlPath, AppName} tuples %% UrlPath = string() %% AppName = atom() %% @spec register_yapp(SrvId::string(), {YappUrl::string(), AppName::atom()}, Registry) -> NewRegistry %% @doc Register a Yapp. Registers in the virtual server with the opaque property %% yapp_server_id = SrvID. The YappUrl is the root path to the Yapp and the AppName is %% the Name of the application. register_yapp(SrvId, {YappUrl, AppName}, YR) -> case proplists:get_value(SrvId,YR) of undefined -> [{SrvId,[{YappUrl,AppName}]} | YR ]; UrlApps -> UrlApps2 = insert({YappUrl,AppName},UrlApps), lists:keyreplace(SrvId, 1, YR, {SrvId,UrlApps2}) end. %% @spec unregister_yapp(SrvId::string(), YappUrl::string()) -> NewRegistry %% @doc Unregister a Yapp. Unregisters in the virtual server with yapp_server_id = SrvID. %% The YappUrl is the root path to the Yapp. unregister_yapp(SrvId, YappUrl, YR) -> case proplists:get_value(SrvId,YR) of undefined -> YR; UrlApps -> case delete(YappUrl, UrlApps) of [] -> lists:keydelete(SrvId,1,YR); UrlApps2 -> lists:keyreplace(SrvId, 1, YR, {SrvId,UrlApps2}) end end. insert({Key,Value}, List)-> case lists:keymember(Key, 1, List) of false -> [{Key,Value}|List]; true -> lists:keyreplace(Key, 1, List, {Key, Value}) end. delete(Key, List) -> case lists:keymember(Key, 1, List) of false -> List; true -> lists:keydelete(Key, 1, List) end. %%-------------------------------------------------------------------- |