1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1996-2020. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(application). 21 22-export([ensure_all_started/1, ensure_all_started/2, start/1, start/2, 23 start_boot/1, start_boot/2, stop/1, 24 load/1, load/2, unload/1, takeover/2, 25 which_applications/0, which_applications/1, 26 loaded_applications/0, permit/2]). 27-export([ensure_started/1, ensure_started/2]). 28-export([set_env/1, set_env/2, set_env/3, set_env/4, unset_env/2, unset_env/3]). 29-export([get_env/1, get_env/2, get_env/3, get_all_env/0, get_all_env/1]). 30-export([get_key/1, get_key/2, get_all_key/0, get_all_key/1]). 31-export([get_application/0, get_application/1, info/0]). 32-export([start_type/0]). 33 34-export_type([start_type/0]). 35 36%%%----------------------------------------------------------------- 37 38-type start_type() :: 'normal' 39 | {'takeover', Node :: node()} 40 | {'failover', Node :: node()}. 41-type restart_type() :: 'permanent' | 'transient' | 'temporary'. 42-type application_opt() :: {'description', Description :: string()} 43 | {'vsn', Vsn :: string()} 44 | {'id', Id :: string()} 45 | {'modules', [Module :: module()]} 46 | {'registered', Names :: [Name :: atom()]} 47 | {'applications', [Application :: atom()]} 48 | {'included_applications', [Application :: atom()]} 49 | {'env', [{Par :: atom(), Val :: term()}]} 50 | {'start_phases', 51 [{Phase :: atom(), PhaseArgs :: term()}] | 'undefined'} 52 | {'maxT', MaxT :: timeout()} % max timeout 53 | {'maxP', 54 MaxP :: pos_integer() | 'infinity'} % max processes 55 | {'mod', Start :: {Module :: module(), StartArgs :: term()}}. 56-type application_spec() :: {'application', 57 Application :: atom(), 58 AppSpecKeys :: [application_opt()]}. 59 60-type(tuple_of(_T) :: tuple()). 61 62%%------------------------------------------------------------------ 63 64-callback start(StartType :: start_type(), StartArgs :: term()) -> 65 {'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}. 66 67-callback stop(State :: term()) -> 68 term(). 69 70%%%----------------------------------------------------------------- 71%%% This module is API towards application_controller and 72%%% application_master. 73%%%----------------------------------------------------------------- 74 75-spec load(AppDescr) -> 'ok' | {'error', Reason} when 76 AppDescr :: Application | (AppSpec :: application_spec()), 77 Application :: atom(), 78 Reason :: term(). 79 80load(Application) -> 81 load1(Application, []). 82 83-spec load(AppDescr, Distributed) -> 'ok' | {'error', Reason} when 84 AppDescr :: Application | (AppSpec :: application_spec()), 85 Application :: atom(), 86 Distributed :: {Application,Nodes} 87 | {Application,Time,Nodes} 88 | 'default', 89 Nodes :: [node() | tuple_of(node())], 90 Time :: pos_integer(), 91 Reason :: term(). 92 93load(Application, DistNodes) -> 94 load1(Application, DistNodes). 95 96%% Workaround due to specs. 97load1(Application, DistNodes) -> 98 case application_controller:load_application(Application) of 99 ok when DistNodes =/= [] -> 100 AppName = get_appl_name(Application), 101 case dist_ac:load_application(AppName, DistNodes) of 102 ok -> 103 ok; 104 {error, R} -> 105 application_controller:unload_application(AppName), 106 {error, R} 107 end; 108 Else -> 109 Else 110 end. 111 112-spec unload(Application) -> 'ok' | {'error', Reason} when 113 Application :: atom(), 114 Reason :: term(). 115 116unload(Application) -> 117 application_controller:unload_application(Application). 118 119 120-spec ensure_all_started(Application) -> {'ok', Started} | {'error', Reason} when 121 Application :: atom(), 122 Started :: [atom()], 123 Reason :: term(). 124ensure_all_started(Application) -> 125 ensure_all_started(Application, temporary). 126 127-spec ensure_all_started(Application, Type) -> {'ok', Started} | {'error', Reason} when 128 Application :: atom(), 129 Type :: restart_type(), 130 Started :: [atom()], 131 Reason :: term(). 132ensure_all_started(Application, Type) -> 133 case ensure_all_started([Application], [], Type, []) of 134 {ok, Started} -> 135 {ok, lists:reverse(Started)}; 136 {error, Reason, Started} -> 137 _ = [stop(App) || App <- Started], 138 {error, Reason} 139 end. 140 141ensure_all_started([App | Apps], OptionalApps, Type, Started) -> 142 %% In case the app is already running, we just skip it instead 143 %% of attempting to start all of its children - which would 144 %% have already been loaded and started anyway. 145 case application_controller:is_running(App) of 146 false -> 147 case ensure_loaded(App) of 148 {ok, Name} -> 149 case ensure_started(Name, App, Type, Started) of 150 {ok, NewStarted} -> 151 ensure_all_started(Apps, OptionalApps, Type, NewStarted); 152 Error -> 153 Error 154 end; 155 {error, {"no such file or directory", _} = Reason} -> 156 case lists:member(App, OptionalApps) of 157 true -> 158 ensure_all_started(Apps, OptionalApps, Type, Started); 159 false -> 160 {error, {App, Reason}, Started} 161 end; 162 {error, Reason} -> 163 {error, {App, Reason}, Started} 164 end; 165 true -> 166 ensure_all_started(Apps, OptionalApps, Type, Started) 167 end; 168ensure_all_started([], _OptionalApps, _Type, Started) -> 169 {ok, Started}. 170 171ensure_started(Name, App, Type, Started) -> 172 {ok, ChildApps} = get_key(Name, applications), 173 {ok, OptionalApps} = get_key(Name, optional_applications), 174 175 case ensure_all_started(ChildApps, OptionalApps, Type, Started) of 176 {ok, NewStarted} -> 177 case application_controller:start_application(Name, Type) of 178 ok -> 179 {ok, [App | NewStarted]}; 180 {error, {already_started, App}} -> 181 {ok, NewStarted}; 182 {error, Reason} -> 183 {error, {App, Reason}, NewStarted} 184 end; 185 Error -> 186 Error 187 end. 188 189-spec start(Application) -> 'ok' | {'error', Reason} when 190 Application :: atom(), 191 Reason :: term(). 192 193start(Application) -> 194 start(Application, temporary). 195 196-spec start(Application, Type) -> 'ok' | {'error', Reason} when 197 Application :: atom(), 198 Type :: restart_type(), 199 Reason :: term(). 200 201start(Application, RestartType) -> 202 case ensure_loaded(Application) of 203 {ok, Name} -> 204 application_controller:start_application(Name, RestartType); 205 Error -> 206 Error 207 end. 208 209ensure_loaded(Application) -> 210 case load(Application) of 211 ok -> 212 {ok, get_appl_name(Application)}; 213 {error, {already_loaded, Name}} -> 214 {ok, Name}; 215 Error -> 216 Error 217 end. 218 219-spec ensure_started(Application) -> 'ok' | {'error', Reason} when 220 Application :: atom(), 221 Reason :: term(). 222 223ensure_started(Application) -> 224 ensure_started(Application, temporary). 225 226-spec ensure_started(Application, Type) -> 'ok' | {'error', Reason} when 227 Application :: atom(), 228 Type :: restart_type(), 229 Reason :: term(). 230 231ensure_started(Application, RestartType) -> 232 case start(Application, RestartType) of 233 ok -> 234 ok; 235 {error, {already_started, Application}} -> 236 ok; 237 Error -> 238 Error 239 end. 240 241-spec start_boot(Application :: atom()) -> 'ok' | {'error', term()}. 242 243start_boot(Application) -> 244 start_boot(Application, temporary). 245 246-spec start_boot(Application :: atom(), RestartType :: restart_type()) -> 247 'ok' | {'error', term()}. 248 249start_boot(Application, RestartType) -> 250 application_controller:start_boot_application(Application, RestartType). 251 252-spec takeover(Application, Type) -> 'ok' | {'error', Reason} when 253 Application :: atom(), 254 Type :: restart_type(), 255 Reason :: term(). 256 257takeover(Application, RestartType) -> 258 dist_ac:takeover_application(Application, RestartType). 259 260-spec permit(Application, Permission) -> 'ok' | {'error', Reason} when 261 Application :: atom(), 262 Permission :: boolean(), 263 Reason :: term(). 264 265permit(Application, Bool) -> 266 case Bool of 267 true -> ok; 268 false -> ok; 269 Bad -> exit({badarg, {?MODULE, permit, [Application, Bad]}}) 270 end, 271 case application_controller:permit_application(Application, Bool) of 272 distributed_application -> 273 dist_ac:permit_application(Application, Bool); 274 {distributed_application, only_loaded} -> 275 dist_ac:permit_only_loaded_application(Application, Bool); 276 LocalResult -> 277 LocalResult 278 end. 279 280-spec stop(Application) -> 'ok' | {'error', Reason} when 281 Application :: atom(), 282 Reason :: term(). 283 284stop(Application) -> 285 application_controller:stop_application(Application). 286 287-spec which_applications() -> [{Application, Description, Vsn}] when 288 Application :: atom(), 289 Description :: string(), 290 Vsn :: string(). 291 292which_applications() -> 293 application_controller:which_applications(). 294 295-spec which_applications(Timeout) -> [{Application, Description, Vsn}] when 296 Timeout :: timeout(), 297 Application :: atom(), 298 Description :: string(), 299 Vsn :: string(). 300 301which_applications(infinity) -> 302 application_controller:which_applications(infinity); 303which_applications(Timeout) when is_integer(Timeout), Timeout>=0 -> 304 application_controller:which_applications(Timeout). 305 306-spec loaded_applications() -> [{Application, Description, Vsn}] when 307 Application :: atom(), 308 Description :: string(), 309 Vsn :: string(). 310 311loaded_applications() -> 312 application_controller:loaded_applications(). 313 314-spec info() -> term(). 315 316info() -> 317 application_controller:info(). 318 319-spec set_env(Config) -> 'ok' when 320 Config :: [{Application, Env}], 321 Application :: atom(), 322 Env :: [{Par :: atom(), Val :: term()}]. 323 324set_env(Config) when is_list(Config) -> 325 set_env(Config, []). 326 327-spec set_env(Config, Opts) -> 'ok' when 328 Config :: [{Application, Env}], 329 Application :: atom(), 330 Env :: [{Par :: atom(), Val :: term()}], 331 Opts :: [{timeout, timeout()} | {persistent, boolean()}]. 332 333set_env(Config, Opts) when is_list(Config), is_list(Opts) -> 334 case application_controller:set_env(Config, Opts) of 335 ok -> ok; 336 {error, Msg} -> erlang:error({badarg, Msg}, [Config, Opts]) 337 end. 338 339-spec set_env(Application, Par, Val) -> 'ok' when 340 Application :: atom(), 341 Par :: atom(), 342 Val :: term(). 343 344set_env(Application, Key, Val) -> 345 application_controller:set_env(Application, Key, Val). 346 347-spec set_env(Application, Par, Val, Opts) -> 'ok' when 348 Application :: atom(), 349 Par :: atom(), 350 Val :: term(), 351 Opts :: [{timeout, timeout()} | {persistent, boolean()}]. 352 353set_env(Application, Key, Val, infinity) -> 354 set_env(Application, Key, Val, [{timeout, infinity}]); 355set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 -> 356 set_env(Application, Key, Val, [{timeout, Timeout}]); 357set_env(Application, Key, Val, Opts) when is_list(Opts) -> 358 application_controller:set_env(Application, Key, Val, Opts). 359 360-spec unset_env(Application, Par) -> 'ok' when 361 Application :: atom(), 362 Par :: atom(). 363 364unset_env(Application, Key) -> 365 application_controller:unset_env(Application, Key). 366 367-spec unset_env(Application, Par, Opts) -> 'ok' when 368 Application :: atom(), 369 Par :: atom(), 370 Opts :: [{timeout, timeout()} | {persistent, boolean()}]. 371 372unset_env(Application, Key, infinity) -> 373 unset_env(Application, Key, [{timeout, infinity}]); 374unset_env(Application, Key, Timeout) when is_integer(Timeout), Timeout>=0 -> 375 unset_env(Application, Key, [{timeout, Timeout}]); 376unset_env(Application, Key, Opts) when is_list(Opts) -> 377 application_controller:unset_env(Application, Key, Opts). 378 379-spec get_env(Par) -> 'undefined' | {'ok', Val} when 380 Par :: atom(), 381 Val :: term(). 382 383get_env(Key) -> 384 application_controller:get_pid_env(group_leader(), Key). 385 386-spec get_env(Application, Par) -> 'undefined' | {'ok', Val} when 387 Application :: atom(), 388 Par :: atom(), 389 Val :: term(). 390 391get_env(Application, Key) -> 392 application_controller:get_env(Application, Key). 393 394-spec get_env(Application, Par, Def) -> Val when 395 Application :: atom(), 396 Par :: atom(), 397 Def :: term(), 398 Val :: term(). 399 400get_env(Application, Key, Def) -> 401 case get_env(Application, Key) of 402 {ok, Val} -> 403 Val; 404 undefined -> 405 Def 406 end. 407 408-spec get_all_env() -> Env when 409 Env :: [{Par :: atom(), Val :: term()}]. 410 411get_all_env() -> 412 application_controller:get_pid_all_env(group_leader()). 413 414-spec get_all_env(Application) -> Env when 415 Application :: atom(), 416 Env :: [{Par :: atom(), Val :: term()}]. 417 418get_all_env(Application) -> 419 application_controller:get_all_env(Application). 420 421-spec get_key(Key) -> 'undefined' | {'ok', Val} when 422 Key :: atom(), 423 Val :: term(). 424 425get_key(Key) -> 426 application_controller:get_pid_key(group_leader(), Key). 427 428-spec get_key(Application, Key) -> 'undefined' | {'ok', Val} when 429 Application :: atom(), 430 Key :: atom(), 431 Val :: term(). 432 433get_key(Application, Key) -> 434 application_controller:get_key(Application, Key). 435 436-spec get_all_key() -> [] | {'ok', Keys} when 437 Keys :: [{Key :: atom(),Val :: term()},...]. 438 439get_all_key() -> 440 application_controller:get_pid_all_key(group_leader()). 441 442-spec get_all_key(Application) -> 'undefined' | Keys when 443 Application :: atom(), 444 Keys :: {'ok', [{Key :: atom(),Val :: term()},...]}. 445 446get_all_key(Application) -> 447 application_controller:get_all_key(Application). 448 449-spec get_application() -> 'undefined' | {'ok', Application} when 450 Application :: atom(). 451 452get_application() -> 453 application_controller:get_application(group_leader()). 454 455-spec get_application(PidOrModule) -> 'undefined' | {'ok', Application} when 456 PidOrModule :: (Pid :: pid()) | (Module :: module()), 457 Application :: atom(). 458 459get_application(Pid) when is_pid(Pid) -> 460 case process_info(Pid, group_leader) of 461 {group_leader, Gl} -> 462 application_controller:get_application(Gl); 463 undefined -> 464 undefined 465 end; 466get_application(Module) when is_atom(Module) -> 467 application_controller:get_application_module(Module). 468 469-spec start_type() -> StartType | 'undefined' | 'local' when 470 StartType :: start_type(). 471 472start_type() -> 473 application_controller:start_type(group_leader()). 474 475%% Internal 476get_appl_name(Name) when is_atom(Name) -> Name; 477get_appl_name({application, Name, _}) when is_atom(Name) -> Name. 478