|
@@ -0,0 +1,86 @@
|
|
|
+-module(nitro_pi).
|
|
|
+-description('NITRO Process Instance'). % gen_server replacement
|
|
|
+-include_lib("nitro/include/nitro_pi.hrl").
|
|
|
+-include_lib("nitro/include/n2o.hrl").
|
|
|
+-behaviour(gen_server).
|
|
|
+-export([start_link/1]).
|
|
|
+-export([init/1,handle_call/3,handle_cast/2,handle_info/2,terminate/2,code_change/3]).
|
|
|
+-export([start/1,stop/2,send/2,send/3,cast/2,cast/3,pid/2,restart/2]).
|
|
|
+
|
|
|
+start(#pi{table=Tab,name=Name,module=Module,sup=Sup,timeout=Timeout,restart=Restart} = Async) ->
|
|
|
+ ChildSpec = {{Tab,Name},{?MODULE,start_link,[Async]},Restart,Timeout,worker,[Module]},
|
|
|
+ case supervisor:start_child(Sup,ChildSpec) of
|
|
|
+ {ok,Pid} -> {Pid,Async#pi.name};
|
|
|
+ {ok,Pid,_} -> {Pid,Async#pi.name};
|
|
|
+ {error,Reason} -> {error,Reason} end.
|
|
|
+
|
|
|
+stop(Tab,Name) ->
|
|
|
+ case nitro_pi:pid(Tab,Name) of
|
|
|
+ Pid when is_pid(Pid) ->
|
|
|
+ #pi{sup=Sup} = Async = send(Pid,{get}),
|
|
|
+ [ supervisor:F(Sup,{Tab,Name})
|
|
|
+ || F <- [ terminate_child , delete_child ] ],
|
|
|
+ cache(Tab,{Tab,Name},undefined),
|
|
|
+ Async;
|
|
|
+ Data -> {error,{not_pid,Data}} end.
|
|
|
+
|
|
|
+send(Pid,Message) when is_pid(Pid) -> gen_server:call(Pid,Message).
|
|
|
+send(Tab,Name,Message) -> gen_server:call(nitro_pi:pid(Tab,Name),Message).
|
|
|
+
|
|
|
+cast(Pid,Message) when is_pid(Pid) -> gen_server:cast(Pid,Message).
|
|
|
+cast(Tab,Name,Message) -> gen_server:cast(nitro_pi:pid(Tab,Name),Message).
|
|
|
+
|
|
|
+cache(Tab, Key) ->
|
|
|
+ Res = ets:lookup(Tab,Key),
|
|
|
+ Val = case Res of [] -> []; [Value] -> Value; Values -> Values end,
|
|
|
+ case Val of [] -> [];
|
|
|
+ {_,{infinity,X}} -> X;
|
|
|
+ {_,{Expire,X}} -> case Expire < calendar:local_time() of
|
|
|
+ true -> ets:delete(Tab,Key), [];
|
|
|
+ false -> X end end.
|
|
|
+cache(Tab, Key, undefined) -> ets:delete(Tab,Key);
|
|
|
+cache(Tab, Key, Value) -> cache(Tab, Key, Value, infinity).
|
|
|
+cache(Tab, Key, Value, Till) -> ets:insert(Tab,{Key,{Till,Value}}), Value.
|
|
|
+
|
|
|
+pid(Tab,Name) -> cache(Tab,{Tab,Name}).
|
|
|
+
|
|
|
+restart(Tab,Name) ->
|
|
|
+ case stop(Tab,Name) of
|
|
|
+ #pi{}=Async -> start(Async);
|
|
|
+ Error -> Error end.
|
|
|
+
|
|
|
+handle(Mod,Message,Async) ->
|
|
|
+ case Mod:proc(Message,Async) of
|
|
|
+ {ok,S} -> {ok,S};
|
|
|
+ {ok,S,T} -> {ok,S,T};
|
|
|
+ {stop,X,Y,S} -> {stop,X,Y,S};
|
|
|
+ {stop,X,S} -> {stop,X,S};
|
|
|
+ {stop,S} -> {stop,S};
|
|
|
+ {reply,X,S,T} -> {reply,X,S,T};
|
|
|
+ {reply,X,S} -> {reply,X,S};
|
|
|
+ {noreply,X,S} -> {noreply,X,S};
|
|
|
+ {noreply,S} -> {noreply,S};
|
|
|
+ {_,S} -> {noreply,S};
|
|
|
+ S -> {noreply,S} end.
|
|
|
+
|
|
|
+start_link (Parameters) -> gen_server:start_link(?MODULE, Parameters, []).
|
|
|
+code_change(_,State,_) -> {ok, State}.
|
|
|
+handle_call({get},_,Async) -> {reply,Async,Async};
|
|
|
+handle_call(_,_,#pi{module=undefined}) -> {noreply,[]};
|
|
|
+handle_call(Message,_,#pi{module=Mod}=Async) -> handle(Mod,Message,Async).
|
|
|
+handle_cast(_, #pi{module=undefined}) -> {noreply,[]};
|
|
|
+handle_cast(Message, #pi{module=Mod}=Async) -> handle(Mod,Message,Async).
|
|
|
+handle_info(timeout, #pi{module=undefined}) -> {noreply,[]};
|
|
|
+handle_info(timeout, #pi{module=Mod}=Async) -> handle(Mod,timeout,Async);
|
|
|
+handle_info(_, #pi{module=undefined}) -> {noreply,[]};
|
|
|
+handle_info(Message, #pi{module=Mod}=Async) -> handle(Mod,Message,Async);
|
|
|
+handle_info(_, _) -> {noreply,[]}.
|
|
|
+
|
|
|
+init(#pi{module=Mod,table=Tab,name=Name}=Handler) ->
|
|
|
+ cache(Tab,{Tab,Name},self(),infinity),
|
|
|
+ Mod:proc(init,Handler).
|
|
|
+
|
|
|
+terminate(_Reason, #pi{name=Name,sup=Sup,table=Tab}) ->
|
|
|
+ spawn(fun() -> supervisor:delete_child(Sup,{Tab,Name}) end),
|
|
|
+ catch cache(Tab,{Tab,Name},undefined), ok.
|
|
|
+
|