%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
-module(application).
-export([ensure_all_started/1, ensure_all_started/2, start/1, start/2,
start_boot/1, start_boot/2, stop/1,
load/1, load/2, unload/1, takeover/2,
which_applications/0, which_applications/1,
loaded_applications/0, permit/2]).
-export([ensure_started/1, ensure_started/2]).
-export([set_env/3, set_env/4, unset_env/2, unset_env/3]).
-export([get_env/1, get_env/2, get_env/3, get_all_env/0, get_all_env/1]).
-export([get_key/1, get_key/2, get_all_key/0, get_all_key/1]).
-export([get_application/0, get_application/1, info/0]).
-export([start_type/0]).
-export_type([start_type/0]).
%%%-----------------------------------------------------------------
-type start_type() :: 'normal'
| {'takeover', Node :: node()}
| {'failover', Node :: node()}.
-type restart_type() :: 'permanent' | 'transient' | 'temporary'.
-type application_opt() :: {'description', Description :: string()}
| {'vsn', Vsn :: string()}
| {'id', Id :: string()}
| {'modules', [Module :: module()]}
| {'registered', Names :: [Name :: atom()]}
| {'applications', [Application :: atom()]}
| {'included_applications', [Application :: atom()]}
| {'env', [{Par :: atom(), Val :: term()}]}
| {'start_phases',
[{Phase :: atom(), PhaseArgs :: term()}] | 'undefined'}
| {'maxT', MaxT :: timeout()} % max timeout
| {'maxP',
MaxP :: pos_integer() | 'infinity'} % max processes
| {'mod', Start :: {Module :: module(), StartArgs :: term()}}.
-type application_spec() :: {'application',
Application :: atom(),
AppSpecKeys :: [application_opt()]}.
-type(tuple_of(_T) :: tuple()).
%%------------------------------------------------------------------
-callback start(StartType :: start_type(), StartArgs :: term()) ->
{'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}.
-callback stop(State :: term()) ->
term().
%%%-----------------------------------------------------------------
%%% This module is API towards application_controller and
%%% application_master.
%%%-----------------------------------------------------------------
-spec load(AppDescr) -> 'ok' | {'error', Reason} when
AppDescr :: Application | (AppSpec :: application_spec()),
Application :: atom(),
Reason :: term().
load(Application) ->
load1(Application, []).
-spec load(AppDescr, Distributed) -> 'ok' | {'error', Reason} when
AppDescr :: Application | (AppSpec :: application_spec()),
Application :: atom(),
Distributed :: {Application,Nodes}
| {Application,Time,Nodes}
| 'default',
Nodes :: [node() | tuple_of(node())],
Time :: pos_integer(),
Reason :: term().
load(Application, DistNodes) ->
load1(Application, DistNodes).
%% Workaround due to specs.
load1(Application, DistNodes) ->
case application_controller:load_application(Application) of
ok when DistNodes =/= [] ->
AppName = get_appl_name(Application),
case dist_ac:load_application(AppName, DistNodes) of
ok ->
ok;
{error, R} ->
application_controller:unload_application(AppName),
{error, R}
end;
Else ->
Else
end.
-spec unload(Application) -> 'ok' | {'error', Reason} when
Application :: atom(),
Reason :: term().
unload(Application) ->
application_controller:unload_application(Application).
-spec ensure_all_started(Application) -> {'ok', Started} | {'error', Reason} when
Application :: atom(),
Started :: [atom()],
Reason :: term().
ensure_all_started(Application) ->
ensure_all_started(Application, temporary).
-spec ensure_all_started(Application, Type) -> {'ok', Started} | {'error', Reason} when
Application :: atom(),
Type :: restart_type(),
Started :: [atom()],
Reason :: term().
ensure_all_started(Application, Type) ->
case ensure_all_started(Application, Type, []) of
{ok, Started} ->
{ok, lists:reverse(Started)};
{error, Reason, Started} ->
_ = [stop(App) || App <- Started],
{error, Reason}
end.
ensure_all_started(Application, Type, Started) ->
case start(Application, Type) of
ok ->
{ok, [Application | Started]};
{error, {already_started, Application}} ->
{ok, Started};
{error, {not_started, Dependency}} ->
case ensure_all_started(Dependency, Type, Started) of
{ok, NewStarted} ->
ensure_all_started(Application, Type, NewStarted);
Error ->
Error
end;
{error, Reason} ->
{error, {Application, Reason}, Started}
end.
-spec start(Application) -> 'ok' | {'error', Reason} when
Application :: atom(),
Reason :: term().
start(Application) ->
start(Application, temporary).
-spec start(Application, Type) -> 'ok' | {'error', Reason} when
Application :: atom(),
Type :: restart_type(),
Reason :: term().
start(Application, RestartType) ->
case load(Application) of
ok ->
Name = get_appl_name(Application),
application_controller:start_application(Name, RestartType);
{error, {already_loaded, Name}} ->
application_controller:start_application(Name, RestartType);
Error ->
Error
end.
-spec ensure_started(Application) -> 'ok' | {'error', Reason} when
Application :: atom(),
Reason :: term().
ensure_started(Application) ->
ensure_started(Application, temporary).
-spec ensure_started(Application, Type) -> 'ok' | {'error', Reason} when
Application :: atom(),
Type :: restart_type(),
Reason :: term().
ensure_started(Application, RestartType) ->
case start(Application, RestartType) of
ok ->
ok;
{error, {already_started, Application}} ->
ok;
Error ->
Error
end.
-spec start_boot(Application :: atom()) -> 'ok' | {'error', term()}.
start_boot(Application) ->
start_boot(Application, temporary).
-spec start_boot(Application :: atom(), RestartType :: restart_type()) ->
'ok' | {'error', term()}.
start_boot(Application, RestartType) ->
application_controller:start_boot_application(Application, RestartType).
-spec takeover(Application, Type) -> 'ok' | {'error', Reason} when
Application :: atom(),
Type :: restart_type(),
Reason :: term().
takeover(Application, RestartType) ->
dist_ac:takeover_application(Application, RestartType).
-spec permit(Application, Permission) -> 'ok' | {'error', Reason} when
Application :: atom(),
Permission :: boolean(),
Reason :: term().
permit(Application, Bool) ->
case Bool of
true -> ok;
false -> ok;
Bad -> exit({badarg, {?MODULE, permit, [Application, Bad]}})
end,
case application_controller:permit_application(Application, Bool) of
distributed_application ->
dist_ac:permit_application(Application, Bool);
{distributed_application, only_loaded} ->
dist_ac:permit_only_loaded_application(Application, Bool);
LocalResult ->
LocalResult
end.
-spec stop(Application) -> 'ok' | {'error', Reason} when
Application :: atom(),
Reason :: term().
stop(Application) ->
application_controller:stop_application(Application).
-spec which_applications() -> [{Application, Description, Vsn}] when
Application :: atom(),
Description :: string(),
Vsn :: string().
which_applications() ->
application_controller:which_applications().
-spec which_applications(Timeout) -> [{Application, Description, Vsn}] when
Timeout :: timeout(),
Application :: atom(),
Description :: string(),
Vsn :: string().
which_applications(infinity) ->
application_controller:which_applications(infinity);
which_applications(Timeout) when is_integer(Timeout), Timeout>=0 ->
application_controller:which_applications(Timeout).
-spec loaded_applications() -> [{Application, Description, Vsn}] when
Application :: atom(),
Description :: string(),
Vsn :: string().
loaded_applications() ->
application_controller:loaded_applications().
-spec info() -> term().
info() ->
application_controller:info().
-spec set_env(Application, Par, Val) -> 'ok' when
Application :: atom(),
Par :: atom(),
Val :: term().
set_env(Application, Key, Val) ->
application_controller:set_env(Application, Key, Val).
-spec set_env(Application, Par, Val, Opts) -> 'ok' when
Application :: atom(),
Par :: atom(),
Val :: term(),
Opts :: [{timeout, timeout()} | {persistent, boolean()}].
set_env(Application, Key, Val, infinity) ->
set_env(Application, Key, Val, [{timeout, infinity}]);
set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 ->
set_env(Application, Key, Val, [{timeout, Timeout}]);
set_env(Application, Key, Val, Opts) when is_list(Opts) ->
application_controller:set_env(Application, Key, Val, Opts).
-spec unset_env(Application, Par) -> 'ok' when
Application :: atom(),
Par :: atom().
unset_env(Application, Key) ->
application_controller:unset_env(Application, Key).
-spec unset_env(Application, Par, Opts) -> 'ok' when
Application :: atom(),
Par :: atom(),
Opts :: [{timeout, timeout()} | {persistent, boolean()}].
unset_env(Application, Key, infinity) ->
unset_env(Application, Key, [{timeout, infinity}]);
unset_env(Application, Key, Timeout) when is_integer(Timeout), Timeout>=0 ->
unset_env(Application, Key, [{timeout, Timeout}]);
unset_env(Application, Key, Opts) when is_list(Opts) ->
application_controller:unset_env(Application, Key, Opts).
-spec get_env(Par) -> 'undefined' | {'ok', Val} when
Par :: atom(),
Val :: term().
get_env(Key) ->
application_controller:get_pid_env(group_leader(), Key).
-spec get_env(Application, Par) -> 'undefined' | {'ok', Val} when
Application :: atom(),
Par :: atom(),
Val :: term().
get_env(Application, Key) ->
application_controller:get_env(Application, Key).
-spec get_env(Application, Par, Def) -> Val when
Application :: atom(),
Par :: atom(),
Def :: term(),
Val :: term().
get_env(Application, Key, Def) ->
case get_env(Application, Key) of
{ok, Val} ->
Val;
undefined ->
Def
end.
-spec get_all_env() -> Env when
Env :: [{Par :: atom(), Val :: term()}].
get_all_env() ->
application_controller:get_pid_all_env(group_leader()).
-spec get_all_env(Application) -> Env when
Application :: atom(),
Env :: [{Par :: atom(), Val :: term()}].
get_all_env(Application) ->
application_controller:get_all_env(Application).
-spec get_key(Key) -> 'undefined' | {'ok', Val} when
Key :: atom(),
Val :: term().
get_key(Key) ->
application_controller:get_pid_key(group_leader(), Key).
-spec get_key(Application, Key) -> 'undefined' | {'ok', Val} when
Application :: atom(),
Key :: atom(),
Val :: term().
get_key(Application, Key) ->
application_controller:get_key(Application, Key).
-spec get_all_key() -> [] | {'ok', Keys} when
Keys :: [{Key :: atom(),Val :: term()},...].
get_all_key() ->
application_controller:get_pid_all_key(group_leader()).
-spec get_all_key(Application) -> 'undefined' | Keys when
Application :: atom(),
Keys :: {'ok', [{Key :: atom(),Val :: term()},...]}.
get_all_key(Application) ->
application_controller:get_all_key(Application).
-spec get_application() -> 'undefined' | {'ok', Application} when
Application :: atom().
get_application() ->
application_controller:get_application(group_leader()).
-spec get_application(PidOrModule) -> 'undefined' | {'ok', Application} when
PidOrModule :: (Pid :: pid()) | (Module :: module()),
Application :: atom().
get_application(Pid) when is_pid(Pid) ->
case process_info(Pid, group_leader) of
{group_leader, Gl} ->
application_controller:get_application(Gl);
undefined ->
undefined
end;
get_application(Module) when is_atom(Module) ->
application_controller:get_application_module(Module).
-spec start_type() -> StartType | 'undefined' | 'local' when
StartType :: start_type().
start_type() ->
application_controller:start_type(group_leader()).
%% Internal
get_appl_name(Name) when is_atom(Name) -> Name;
get_appl_name({application, Name, _}) when is_atom(Name) -> Name.