application_controller.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,925 行 · 第 1/5 页

ERL
1,925
字号
	[[AppName]] -> get_all_key(AppName);	_ -> []    end.get_all_key(AppName) ->    case ets:lookup(ac_tab, {loaded, AppName}) of	[{_, Appl}] ->	    {ok, [{description, Appl#appl.descr},		  {id, Appl#appl.id},		  {vsn, Appl#appl.vsn},		  {modules, (Appl#appl.appl_data)#appl_data.mods},		  {maxP, (Appl#appl.appl_data)#appl_data.maxP},		  {maxT, (Appl#appl.appl_data)#appl_data.maxT},		  {registered, (Appl#appl.appl_data)#appl_data.regs},		  {included_applications, Appl#appl.inc_apps},		  {applications, Appl#appl.apps},		  {env, get_all_env(AppName)},		  {mod, (Appl#appl.appl_data)#appl_data.mod},		  {start_phases, (Appl#appl.appl_data)#appl_data.phases}		 ]};	_ -> 	    undefined    end.start_type(Master) ->    case ets:match(ac_tab, {{application_master, '$1'}, Master}) of	[[AppName]] -> 	    gen_server:call(?AC, {start_type, AppName}, infinity);	_X -> 	    undefined    end.get_master(AppName) ->    case ets:lookup(ac_tab, {application_master, AppName}) of	[{_, Pid}] -> Pid;	_ -> undefined    end.get_application(Master) ->    case ets:match(ac_tab, {{application_master, '$1'}, Master}) of	[[AppName]] -> {ok, AppName};	_ -> undefined    end.get_application_module(Module) ->    ApplDataPattern = #appl_data{mods='$2', _='_'},    ApplPattern = #appl{appl_data=ApplDataPattern, _='_'},    AppModules = ets:match(ac_tab, {{loaded, '$1'}, ApplPattern}),    get_application_module(Module, AppModules).get_application_module(Module, [[AppName, Modules]|AppModules]) ->    case in_modules(Module, Modules) of	true ->	    {ok, AppName};	false ->	    get_application_module(Module, AppModules)    end;get_application_module(_Module, []) ->    undefined.%% 'modules' key in .app is a list of Module or {Module,Vsn}in_modules(Module, [Module|_Modules]) ->    true;in_modules(Module, [{Module, _Vsn}|_Modules]) ->    true;in_modules(Module, [_Module|Modules]) ->    in_modules(Module, Modules);in_modules(_Module, []) ->    false.permit_application(ApplName, Flag) ->    gen_server:call(?AC, 		    {permit_application, ApplName, Flag},		    infinity).set_env(AppName, Key, Val) ->    gen_server:call(?AC, {set_env, AppName, Key, Val}).set_env(AppName, Key, Val, Timeout) ->    gen_server:call(?AC, {set_env, AppName, Key, Val}, Timeout).unset_env(AppName, Key) ->    gen_server:call(?AC, {unset_env, AppName, Key}).unset_env(AppName, Key, Timeout) ->    gen_server:call(?AC, {unset_env, AppName, Key}, Timeout).%%%-----------------------------------------------------------------%%% call-back functions from gen_server%%%-----------------------------------------------------------------init(Init, Kernel) ->    register(?AC, self()),    process_flag(trap_exit, true),    put('$ancestors', [Init]), % OTP-5811, for gen_server compatibility    put('$initial_call', {application_controller, start, [Kernel]}),    case catch check_conf() of	{ok, ConfData} ->	    %% Actually, we don't need this info in an ets table anymore.	    %% This table was introduced because starting applications	    %% should be able to get som info from AC (e.g. loaded_apps).	    %% The new implementation makes sure the AC process can be	    %% called during start-up of any app.	    case check_conf_data(ConfData) of		ok ->		    ets:new(ac_tab, [set, public, named_table]),		    S = #state{conf_data = ConfData},		    {ok, KAppl} = make_appl(Kernel),		    case catch load(S, KAppl) of			{'EXIT', LoadError} ->			    Reason = {'load error', LoadError},			    Init ! {ack, self(), {error, to_string(Reason)}};			{ok, NewS} ->			    Init ! {ack, self(), ok},			    gen_server:enter_loop(?MODULE, [], NewS,						  {local, ?AC})		    end;		{error, ErrorStr} ->		    Str = lists:flatten(io_lib:format("invalid config data: ~s", [ErrorStr])),		    Init ! {ack, self(), {error, to_string(Str)}}	    end;	{error, {File, Line, Str}} ->	    ReasonStr =		lists:flatten(io_lib:format("error in config file "					    "~p (~w): ~s",					    [File, Line, Str])),	    Init ! {ack, self(), {error, to_string(ReasonStr)}}    end.%% Check the syntax of the .config file  [{ApplicationName, [{Parameter, Value}]}].check_conf_data([]) ->    ok;check_conf_data(ConfData) when is_list(ConfData) ->    [Application | ConfDataRem] = ConfData,    case Application of	{kernel, List} when is_list(List) ->	    case check_para_kernel(List) of		ok ->		    check_conf_data(ConfDataRem);		Error1 ->		    Error1	    end;	{AppName, List} when is_atom(AppName), is_list(List) ->	    case check_para(List, atom_to_list(AppName)) of		ok ->		    check_conf_data(ConfDataRem);		Error2 ->		    Error2	    end;	{AppName, List} when is_list(List)  ->	    ErrMsg = "application: "		++ lists:flatten(io_lib:format("~p",[AppName]))		++ "; application name must be an atom",	    {error, ErrMsg};	{AppName, _List} ->	    ErrMsg = "application: "		++ lists:flatten(io_lib:format("~p",[AppName]))		++ "; parameters must be a list",	    {error, ErrMsg};	Else ->	    ErrMsg = "invalid application name: " ++ 		lists:flatten(io_lib:format(" ~p",[Else])),	    {error, ErrMsg}    end;check_conf_data(_ConfData) ->    {error, 'configuration must be a list ended by <dot><whitespace>'}.    %% Special check of distributed parameter for kernelcheck_para_kernel([]) ->    ok;check_para_kernel([{distributed, Apps} | ParaList]) when is_list(Apps) ->    case check_distributed(Apps) of	{error, ErrorMsg} ->	    {error, ErrorMsg};	_ ->	    check_para_kernel(ParaList)    end;check_para_kernel([{distributed, _Apps} | _ParaList]) ->    {error, "application: kernel; erroneous parameter: distributed"};check_para_kernel([{Para, _Val} | ParaList]) when is_atom(Para) ->    check_para_kernel(ParaList);check_para_kernel([{Para, _Val} | _ParaList]) ->    {error, "application: kernel; invalid parameter: " ++      lists:flatten(io_lib:format("~p",[Para]))};check_para_kernel(Else) ->    {error, "application: kernel; invalid parameter list: " ++      lists:flatten(io_lib:format("~p",[Else]))}.    check_distributed([]) ->    ok;check_distributed([{App, List} | Apps]) when is_atom(App), is_list(List) ->    check_distributed(Apps);check_distributed([{App, infinity, List} | Apps]) when is_atom(App), is_list(List) ->    check_distributed(Apps);check_distributed([{App, Time, List} | Apps]) when is_atom(App), is_integer(Time), is_list(List) ->    check_distributed(Apps);check_distributed(_Else) ->    {error, "application: kernel; erroneous parameter: distributed"}.check_para([], _AppName) ->    ok;check_para([{Para, _Val} | ParaList], AppName) when is_atom(Para) ->    check_para(ParaList, AppName);check_para([{Para, _Val} | _ParaList], AppName) ->    {error, "application: " ++ AppName ++ "; invalid parameter: " ++      lists:flatten(io_lib:format("~p",[Para]))};check_para([Else | _ParaList], AppName) ->    {error, "application: " ++ AppName ++ "; invalid parameter: " ++      lists:flatten(io_lib:format("~p",[Else]))}.handle_call({load_application, Application}, From, S) ->    case catch do_load_application(Application, S) of	{ok, NewS} ->	    AppName = get_appl_name(Application),	    case cntrl(AppName, S, {ac_load_application_req, AppName}) of		true ->		    {noreply, S#state{loading = [{AppName, From} |						 S#state.loading]}};		false ->		    {reply, ok, NewS}	    end;	{error, Error} ->	    {reply, {error, Error}, S};	{'EXIT',R} -> 	    {reply, {error, R}, S}    end;handle_call({unload_application, AppName}, _From, S) ->    case keysearch(AppName, 1, S#state.running) of	{value, _} -> {reply, {error, {running, AppName}}, S};	false ->	    case get_loaded(AppName) of		{true, _} ->		    NewS = unload(AppName, S),		    cntrl(AppName, S, {ac_application_unloaded, AppName}),		    {reply, ok, NewS};		false ->		    {reply, {error, {not_loaded, AppName}}, S}	    end    end;handle_call({start_application, AppName, RestartType}, From, S) ->    #state{running = Running, starting = Starting, start_p_false = SPF, 	   started = Started, start_req = Start_req} = S,    %% Check if the commandline environment variables are OK.    %% Incase of erroneous variables do not start the application,    %% if the application is permanent crash the node.    %% Check if the application is already starting.    case lists:keysearch(AppName, 1, Start_req) of	false ->	    case catch check_start_cond(AppName, RestartType, Started, Running) of		{ok, Appl} ->		    Cntrl = cntrl(AppName, S, {ac_start_application_req, AppName}),		    Perm = application:get_env(kernel, permissions),		    case {Cntrl, Perm} of			{true, _} ->			    {noreply, S#state{starting = [{AppName, RestartType, normal, From} |							  Starting],					      start_req = [{AppName, From} | Start_req]}};			{false, undefined} ->			    spawn_starter(From, Appl, S, normal),			    {noreply, S#state{starting = [{AppName, RestartType, normal, From} |							  Starting],					      start_req = [{AppName, From} | Start_req]}};			{false, {ok, Perms}} ->			    case lists:member({AppName, false}, Perms) of				false ->				    spawn_starter(From, Appl, S, normal),				    {noreply, S#state{starting = [{AppName, RestartType, normal, From} |								  Starting],						      start_req = [{AppName, From} | Start_req]}};				true ->				    SS = S#state{start_p_false = [{AppName, RestartType, normal, From} |								  SPF]},				    {reply, ok, SS}			    end		    end;		{error, R} ->		    {reply, {error, R}, S}	    end;	{value, {AppName, _FromX}} ->	    SS = S#state{start_req = [{AppName, From} | Start_req]},	    {noreply, SS}	        end;handle_call({permit_application, AppName, Bool}, From, S) ->    Control = S#state.control,    Starting = S#state.starting,    SPF = S#state.start_p_false,    Started = S#state.started,    Running = S#state.running,    Start_req = S#state.start_req,    IsLoaded = get_loaded(AppName),    IsStarting = lists:keysearch(AppName, 1, Starting),    IsSPF = lists:keysearch(AppName, 1, SPF),    IsStarted = lists:keysearch(AppName, 1, Started),    IsRunning = lists:keysearch(AppName, 1, Running),    case keysearch(AppName, 1, Control) of	%%========================	%% distributed application	%%========================	{value, _} ->	    case {IsLoaded, IsStarting, IsStarted} of		%% not loaded		{false, _, _} ->		    {reply, {error, {not_loaded, AppName}}, S};		%% only loaded		{{true, _Appl}, false, false} ->		    update_permissions(AppName, Bool),		    {reply, {distributed_application, only_loaded}, S};		_ ->		    update_permissions(AppName, Bool),		    {reply, distributed_application, S}	    end;	%%========================	%% local application	%%========================	false ->	    case {Bool, IsLoaded, IsStarting, IsSPF, IsStarted, IsRunning} of		%%------------------------		%% permit the applicaition		%%------------------------		%% already running		{true, _, _, _, _, {value, _Tuple}} ->		    {reply, ok, S};		%% not loaded		{true, false, _, _, _, _} ->		    {reply, {error, {not_loaded, AppName}}, S};		%% only loaded		{true, {true, _Appl}, false, false, false, false} ->		    update_permissions(AppName, Bool),                    {reply, ok, S}; 		%% starting		{true, {true, _Appl}, {value, _Tuple}, false, false, false} ->		    update_permissions(AppName, Bool),                    {reply, ok, S}; %% check the permission after then app is started		%% start requested but not started because permit was false		{true, {true, Appl}, false, {value, Tuple}, false, false} ->		    update_permissions(AppName, Bool),		    {_AppName2, RestartType, normal, _From} = Tuple,		    spawn_starter(From, Appl, S, normal),		    SS = S#state{starting = [{AppName, RestartType, normal, From} | Starting], 				 start_p_false = keydelete(AppName, 1, SPF),				 start_req = [{AppName, From} | Start_req]},		    {noreply, SS};		%% started but not running		{true, {true, Appl}, _, _, {value, {AppName, RestartType}}, false} ->		    update_permissions(AppName, Bool),		    spawn_starter(From, Appl, S, normal),		    SS = S#state{starting = [{AppName, RestartType, normal, From} | Starting], 				 started = keydelete(AppName, 1, Started),				 start_req = [{AppName, From} | Start_req]},		    {noreply, SS};		%%==========================		%% unpermit the applicaition		%%==========================		%% running		{false, _, _, _,  _, {value, {_AppName, Id}}} ->		    {value, {_AppName2, Type}} = keysearch(AppName, 1, Started),		    stop_appl(AppName, Id, Type),		    NRunning = keydelete(AppName, 1, Running),		    {reply, ok, S#state{running = NRunning}};		%% not loaded		{false, false, _, _, _,  _} ->		    {reply, {error, {not_loaded, AppName}}, S};		%% only loaded		{false, {true, _Appl}, false, false, false, false} ->		    update_permissions(AppName, Bool),                    {reply, ok, S}; 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?