%%--------------------------------------------------------------------
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2000-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%
%%
%%
%%----------------------------------------------------------------------
%% File : cosTime.erl
%% Purpose :
%%----------------------------------------------------------------------
-module(cosTime).
%%--------------- INCLUDES -----------------------------------
-include("cosTimeApp.hrl").
%%--------------- EXPORTS-------------------------------------
%% cosTime API external
-export([start/0, stop/0,
install_time/0, uninstall_time/0,
install_timerevent/0, uninstall_timerevent/0,
start_time_service/2, start_timerevent_service/1, stop_timerevent_service/1,
stop_time_service/1]).
%% cosTime API internal
-export([create_link/3, get_option/3, type_check/2, start_event_handler/1]).
%% Application callbacks
-export([start/2, init/1, stop/1]).
%%--------------- DEFINES ------------------------------------
-define(IDL_TIME_MODULES, ['oe_TimeBase',
'oe_CosTime']).
-define(IDL_TIMEREVENT_MODULES, ['oe_CosTimerEvent']).
-define(SUPERVISOR_NAME, oe_cosTimeSup).
-define(SUP_FLAG, {simple_one_for_one,50,10}).
-define(SUP_TIMESERVICE_SPEC(T,I),
['CosTime_TimeService',[T, I],
[{sup_child, true}, {regname, {global, "oe_cosTimeService"}}]]).
-define(SUP_TIMEREVENTSERVICE_SPEC(Args),
['CosTimerEvent_TimerEventService', Args,
[{sup_child, true}, {regname, {local, 'oe_cosTimerEventService'}}]]).
-define(SUP_TIMEREVENTHANDLER_SPEC(Name, Args),
['CosTimerEvent_TimerEventHandler',Args,
[{sup_child, true}, {regname, {global, Name}}]]).
-define(SUP_CHILD,
{"oe_TimeChild",
{cosTime,create_link, []},
transient,100000,worker,
[]}).
%%------------------------------------------------------------
%% function : install_*/X
%% Arguments: - | Time (seconds)
%% Returns : ok | EXIT | EXCEPTION
%% Effect : Install necessary data in the IFR DB
%%------------------------------------------------------------
install_time() ->
case install_loop(?IDL_TIME_MODULES,[]) of
ok ->
ok;
{error, Reason} ->
exit(Reason)
end.
install_timerevent() ->
case install_loop(?IDL_TIMEREVENT_MODULES,[]) of
ok ->
ok;
{error, Reason} ->
exit(Reason)
end.
install_loop([], _) ->
ok;
install_loop([H|T], Accum) ->
case catch H:'oe_register'() of
{'EXIT',{unregistered,App}} ->
?write_ErrorMsg("Unable to register '~p'; application ~p not registered.\n"
"Trying to unregister ~p\n", [H,App,Accum]),
uninstall_loop(Accum, {exit, register});
{'EXCEPTION',_} ->
?write_ErrorMsg("Unable to register '~p'; propably already registered.\n"
"You are adviced to confirm this.\n"
"Trying to unregister ~p\n", [H,Accum]),
uninstall_loop(Accum, {exit, register});
ok ->
install_loop(T, [H|Accum]);
_ ->
?write_ErrorMsg("Unable to register '~p'; reason unknown.\n"
"Trying to unregister ~p\n", [H,Accum]),
uninstall_loop(Accum, {exit, register})
end.
%%------------------------------------------------------------
%% function : uninstall_*/X
%% Arguments: - | Time (seconds)
%% Returns : ok | EXIT | EXCEPTION
%% Effect : Remove data related to cosTime from the IFR DB
%%------------------------------------------------------------
uninstall_time() ->
case uninstall_loop(lists:reverse(?IDL_TIME_MODULES),ok) of
ok ->
ok;
{error, Reason} ->
exit(Reason)
end.
uninstall_timerevent() ->
case uninstall_loop(lists:reverse(?IDL_TIMEREVENT_MODULES),ok) of
ok ->
ok;
{error, Reason} ->
exit(Reason)
end.
uninstall_loop([],ok) ->
ok;
uninstall_loop([],{exit, register}) ->
{error, {?MODULE, "oe_register failed"}};
uninstall_loop([],{exit, unregister}) ->
{error, {?MODULE, "oe_unregister failed"}};
uninstall_loop([],{exit, both}) ->
{error, {?MODULE, "oe_register and, for some of those already registered, oe_unregister failed"}};
uninstall_loop([H|T], Status) ->
case catch H:'oe_unregister'() of
ok ->
uninstall_loop(T, Status);
_ when Status == ok ->
?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n"
"You are adviced to confirm this.~n",[H]),
uninstall_loop(T, {exit, unregister});
_ ->
?write_ErrorMsg("Unable to unregister '~p'; propably already unregistered.\n"
"You are adviced to confirm this.~n",[H]),
uninstall_loop(T, {exit, both})
end.
%%------------------------------------------------------------
%% function : start/stop
%% Arguments:
%% Returns :
%% Effect : Starts or stops the cosTime application.
%%------------------------------------------------------------
start() ->
application:start(cosTime).
stop() ->
application:stop(cosTime).
%%------------------------------------------------------------
%% function : start
%% Arguments: Type - see module application
%% Arg - see module application
%% Returns :
%% Effect : Module callback for application
%%------------------------------------------------------------
start(_, _) ->
supervisor:start_link({local, ?SUPERVISOR_NAME}, cosTime, app_init).
%%------------------------------------------------------------
%% function : stop
%% Arguments: Arg - see module application
%% Returns :
%% Effect : Module callback for application
%%------------------------------------------------------------
stop(_) ->
ok.
%%------------------------------------------------------------
%% function : start_time_service
%% Arguments: Tdf - time difference to UTC
%% Inaccuracy - ulonglong
%% Upper - inaccuracy high
%% Returns :
%% Effect :
%%------------------------------------------------------------
start_time_service(Tdf, Inaccuracy) when is_integer(Tdf) andalso is_integer(Inaccuracy) ->
case supervisor:start_child(?SUPERVISOR_NAME,
?SUP_TIMESERVICE_SPEC(Tdf, Inaccuracy)) of
{ok, Pid, Obj} when is_pid(Pid) ->
Obj;
_Other->
corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
end;
start_time_service(_Tdf, _Inaccuracy) ->
corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}).
%%------------------------------------------------------------
%% function : stop_time_service
%% Arguments: Obj - TimeService objref
%% Returns :
%% Effect :
%%------------------------------------------------------------
stop_time_service(Obj) ->
corba:dispose(Obj).
%%------------------------------------------------------------
%% function : start_timerevent_service
%% Arguments: Timer - Timer Service Reference
%% Returns :
%% Effect :
%%------------------------------------------------------------
start_timerevent_service(Timer) ->
case supervisor:start_child(?SUPERVISOR_NAME,
?SUP_TIMEREVENTSERVICE_SPEC([Timer])) of
{ok, Pid, Obj} when is_pid(Pid) ->
Obj;
_Other->
corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
end.
%%-----------------------------------------------------------%
%% function : stop_timerevent_service
%% Arguments: Obj - TimerEventService objref
%% Returns :
%% Effect :
%%------------------------------------------------------------
stop_timerevent_service(Obj) ->
corba:dispose(Obj).
%%-----------------------------------------------------------%
%% function : init
%% Arguments:
%% Returns :
%% Effect :
%%------------------------------------------------------------
%% Starting using create_factory/X
init(own_init) ->
{ok,{?SUP_FLAG, [?SUP_CHILD]}};
%% When starting as an application.
init(app_init) ->
{ok,{?SUP_FLAG, [?SUP_CHILD]}}.
%%-----------------------------------------------------------%
%% function : create_link
%% Arguments: Module - which Module to call
%% Env/ArgList - ordinary oe_create arguments.
%% Returns :
%% Exception:
%% Effect : Necessary since we want the supervisor to be a
%% 'simple_one_for_one'. Otherwise, using for example,
%% 'one_for_one', we have to call supervisor:delete_child
%% to remove the childs startspecification from the
%% supervisors internal state.
%%------------------------------------------------------------
create_link(Module, Env, ArgList) ->
Module:oe_create_link(Env, ArgList).
%%-----------------------------------------------------------%
%% function : start_event_handler
%% Arguments:
%% Returns :
%% Exception:
%% Effect :
%%------------------------------------------------------------
start_event_handler(Args) ->
Name = create_name(eventhandler),
case supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TIMEREVENTHANDLER_SPEC(Name,Args)) of
{ok, Pid, Obj} when is_pid(Pid) ->
Obj;
_Other->
corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
end.
%%-----------------------------------------------------------%
%% function : get_option
%% Arguments:
%% Returns :
%% Exception:
%% Effect :
%%------------------------------------------------------------
get_option(Key, OptionList, DefaultList) ->
case lists:keysearch(Key, 1, OptionList) of
{value,{Key,Value}} ->
Value;
_ ->
case lists:keysearch(Key, 1, DefaultList) of
{value,{Key,Value}} ->
Value;
_->
{error, "Invalid option"}
end
end.
%%-----------------------------------------------------------%
%% function : type_check
%% Arguments: Obj - objectrefernce to test.
%% Mod - Module which contains typeID/0.
%% Returns : 'ok' or raises exception.
%% Effect :
%%------------------------------------------------------------
type_check(Obj, Mod) ->
case catch corba_object:is_a(Obj,Mod:typeID()) of
true ->
ok;
_ ->
corba:raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO})
end.
%%-----------------------------------------------------------%
%% function : create_name/1
%% Arguments:
%% Returns :
%% Exception:
%% Effect :
%%------------------------------------------------------------
create_name(Type) ->
Time = erlang:system_time(),
Unique = erlang:unique_integer([positive]),
lists:concat(['oe_',node(),'_',Type,'_',Time,'_',Unique]).
%%--------------- END OF MODULE ------------------------------