diff options
Diffstat (limited to 'lib/orber/src/corba.erl')
-rw-r--r-- | lib/orber/src/corba.erl | 2206 |
1 files changed, 0 insertions, 2206 deletions
diff --git a/lib/orber/src/corba.erl b/lib/orber/src/corba.erl deleted file mode 100644 index 23ce01ffc3..0000000000 --- a/lib/orber/src/corba.erl +++ /dev/null @@ -1,2206 +0,0 @@ -%%-------------------------------------------------------------------- -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2017. 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: corba.erl -%% -%% Description: -%% This file contains the CORBA::ORB interface plus some -%% Orber specific functions. -%%----------------------------------------------------------------- --module(corba). - --include_lib("orber/include/corba.hrl"). --include_lib("orber/src/orber_iiop.hrl"). - -%%----------------------------------------------------------------- -%% Standard interface CORBA -%%----------------------------------------------------------------- --export([orb_init/1, orb_init/2]). -%%----------------------------------------------------------------- -%% Standard interface CORBA::ORB -%%----------------------------------------------------------------- --export([%create_list/2, - %create_operation_list/2, - %% get_default_context/1, - %% 'BOA_init/2, - resolve_initial_references/1, - resolve_initial_references/2, - resolve_initial_references_local/1, - list_initial_services/0, - add_initial_service/2, - remove_initial_service/1, - resolve_initial_references_remote/2, - resolve_initial_references_remote/3, - list_initial_services_remote/1, - list_initial_services_remote/2, - object_to_string/1, object_to_string/2, - object_to_string/3, object_to_string/4, - string_to_object/1, - string_to_object/2]). - -%%----------------------------------------------------------------- -%% External exports -%%----------------------------------------------------------------- --export([create/2, - create/3, - create/4, - create_link/2, - create_link/3, - create_link/4, - create_remote/3, - create_remote/5, - create_link_remote/3, - create_link_remote/5, - create_nil_objref/0, - dispose/1, - create_subobject_key/2, - get_subobject_key/1, - get_pid/1, - raise/1, raise_with_state/2, - print_object/1, - print_object/2, - add_alternate_iiop_address/3, - add_FTGroup_component/4, - add_FTPrimary_component/1, - call_internal/10]). - -%%----------------------------------------------------------------- -%% Internal (inside orber implementation) exports -%%----------------------------------------------------------------- --export([call/4, call/5, reply/2, - cast/4, cast/5, locate/1, locate/2, locate/3, - request_from_iiop/6, - common_create/5, - mk_objkey/4, - mk_light_objkey/2, - objkey_to_string/1, - string_to_objkey/1, - string_to_objkey_local/1, - call_relay/3, - cast_relay/2, - handle_init/2, - handle_terminate/3, - handle_info/3, - handle_code_change/4, - handle_call/7, - handle_call/10, - handle_cast/9, - handle_cast/6, - get_implicit_context/1]). - -%%----------------------------------------------------------------- -%% Internal definitions -%%----------------------------------------------------------------- --define(DEBUG_LEVEL, 5). - --record(is, {flags = 0}). - -%% Defines possible configuration parameters a user can add when -%% creating new CORBA objects. --record(options, {sup_child = false, - persistent = false, - regname = [], - pseudo = false, - object_flags = ?ORB_INIT_FLAGS, - object_flags_set = ?ORB_INIT_FLAGS, - create_options = [], - passive = false, - group_id = 0, - internal_state}). - --record(extra, {timeout = infinity, - context = []}). - - -%%-------------------------------------------------------------------- -%% FT stuff -%%-------------------------------------------------------------------- --define(IDL_MODULES, [oe_TimeBase, - oe_CosEventComm, - oe_CosEventChannelAdmin, - oe_CosNotification, - oe_CosNotifyComm, - oe_CosNotifyFilter, - oe_GIOP]). - --define(groupid_to_table(Integer), - list_to_atom("ft_" ++ integer_to_list(Integer))). - --define(RM_TABLE_SPEC, - [{attributes, record_info(fields, ft_replication_manager)}]). --define(RO_TABLE_SPEC, - [{attributes, record_info(fields, ft_replicated_object)}]). --define(RR_TABLE_SPEC, - [{attributes, record_info(fields, ft_reply_retention)}]). - -%% how long we're allowed to wait for database tables to be available. --define(TABLE_TIMEOUT, infinite). - -%-record(rm_state, {default_options, type_options, node_port_ips}). - -%-record(node_port_ip, {node, port, ip}). - --record(ft_replication_manager, {object_group_id, - type_id, - primary, - iogr, - ref_version, - options}). - --record(ft_replicated_object, {group_id, state}). --record(ft_reply_retention, {retention_id, reply}). - -%-record(ft_properties, {replications_style, -% membership_style, -% consistency_style, -% initial_number_replicas, -% minimum_number_replicas}). - -% one should change things work with stdlib:proplist and clean up the mess. -%-record(ft_criteria, {ft_properties, -% object_location, -% object_init, -% object_impl}). - -%%------------------------------------------------------------ -%% -%% Implementation of CORBA CORBA::ORB interfaces -%% -%%------------------------------------------------------------ - -%%create_list(Count) -> -%% corba_nvlist:create_list(Count). - -%%create_operation_list(OpDef) -> -%% corba_nvlist:create_operation_list(OpDef). - -orb_init(KeyValueList) -> - orb_init(KeyValueList, "ORBER"). - -orb_init([], _Name) -> - ok; -orb_init(KeyValueList, _Name) -> - orber:multi_configure(KeyValueList). - -%%----------------------------------------------------------------- -%% Initial reference handling -%%----------------------------------------------------------------- -resolve_initial_references(ObjectId) -> - resolve_initial_references(ObjectId, []). -resolve_initial_references(ObjectId, Ctx) -> - case use_local_host(ObjectId) of - true -> - orber_initial_references:get(ObjectId); - Ref -> - string_to_object(Ref, Ctx) - end. - -resolve_initial_references_local(ObjectId) -> - orber_initial_references:get(ObjectId). - -list_initial_services() -> - Local = orber_initial_references:list(), - case orber:get_ORBInitRef() of - undefined -> - Local; - InitRef -> - orber_tb:unique(Local ++ get_prefixes(InitRef, [])) - end. - -get_prefixes([], Acc) -> - Acc; -%% A list of ORBInitRef's -get_prefixes([H|T], Acc) when is_list(H) -> - [Key|_] = string:tokens(H, "="), - get_prefixes(T, [Key|Acc]); -%% A single ORBInitRef -get_prefixes(InitRef, _Acc) when is_list(InitRef) -> - [Key|_] = string:tokens(InitRef, "="), - [Key]; -get_prefixes(What, _) -> - orber:dbg("[~p] corba:get_prefixes(~p);~nMalformed argument?", - [?LINE, What], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}). - - -use_local_host(ObjectId) -> - case orber:get_ORBInitRef() of - undefined -> - case orber:get_ORBDefaultInitRef() of - undefined -> - true; - DefRef -> - DefRef++"/"++ObjectId - end; - InitRef -> - case check_prefixes(InitRef, ObjectId) of - false -> - case orber:get_ORBDefaultInitRef() of - undefined -> - true; - DefRef -> - DefRef++"/"++ObjectId - end; - UseRef -> - strip_junk(UseRef) - end - end. - - -check_prefixes([], _) -> - false; -%% A list of ORBInitRef's -check_prefixes([H|T], ObjectId) when is_list(H) -> - case prefix(ObjectId, H) of - false -> - check_prefixes(T, ObjectId); - UseRef -> - UseRef - end; -%% A single ORBInitRef -check_prefixes(InitRef, ObjectId) when is_list(InitRef) -> - case prefix(ObjectId, InitRef) of - false -> - false; - UseRef -> - UseRef - end; -check_prefixes(What,_) -> - orber:dbg("[~p] corba:check_prefixes(~p);~nMalformed argument?", - [?LINE, What], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}). - - -%% Valid is, for example, "NameService = corbaloc::host/NameService". -%% Hence, we must remove ' ' and '='. -strip_junk([32|T]) -> - strip_junk(T); -strip_junk([$=|T]) -> - strip_junk(T); -strip_junk(Ref) -> - Ref. - -add_initial_service(ObjectId, ObjectRef) -> - orber_initial_references:add(ObjectId, ObjectRef). - -remove_initial_service(ObjectId) -> - orber_initial_references:remove(ObjectId). - -resolve_initial_references_remote(ObjectId, Address) -> - resolve_initial_references_remote(ObjectId, Address, []). - -resolve_initial_references_remote(_ObjectId, [], _Ctx) -> - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); -resolve_initial_references_remote(ObjectId, [RemoteModifier| Rest], Ctx) - when is_list(RemoteModifier) -> - case parse_remote_modifier(RemoteModifier) of - {error, _} -> - resolve_initial_references_remote(ObjectId, Rest, Ctx); - {ok, Host, Port} -> - IOR = iop_ior:create_external(orber:giop_version(), "", - Host, list_to_integer(Port), "INIT"), - %% We know it's an external referens. Hence, no need to check. - {_, Key} = iop_ior:get_key(IOR), - orber_iiop:request(Key, 'get', [ObjectId], - {{'tk_objref', 12, "object"}, - [{'tk_string', 0}], - []}, 'true', infinity, IOR, Ctx) - end. - -list_initial_services_remote(Address) -> - list_initial_services_remote(Address, []). - -list_initial_services_remote([], _Ctx) -> - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}); -list_initial_services_remote([RemoteModifier| Rest], Ctx) when is_list(RemoteModifier) -> - case parse_remote_modifier(RemoteModifier) of - {error, _} -> - resolve_initial_references_remote(Rest, Ctx); - {ok, Host, Port} -> - IOR = iop_ior:create_external(orber:giop_version(), "", - Host, list_to_integer(Port), "INIT"), - %% We know it's an external referens. Hence, no need to check. - {_, Key} = iop_ior:get_key(IOR), - orber_iiop:request(Key, 'list', [], - {{'tk_sequence', {'tk_string',0},0}, - [], []}, 'true', infinity, IOR, Ctx) - end; -list_initial_services_remote(_, _) -> - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). - - -parse_remote_modifier("iiop://" ++ Rest) -> - parse_host_version(Rest); -parse_remote_modifier(_RemoteModifier) -> - {error, not_supported}. - -parse_host_version("[" ++ Rest) -> - parse_ipv6(Rest, []); -parse_host_version(Rest) -> - parse_ipv4_or_dnsname(Rest, []). - - -parse_ipv4_or_dnsname([$: |Rest], Acc) -> - {ok, lists:reverse(Acc), Rest}; -parse_ipv4_or_dnsname([C |Rest], Acc) -> - parse_ipv4_or_dnsname(Rest, [C |Acc]). - -parse_ipv6("]:" ++ Rest, Acc) -> - {ok, lists:reverse(Acc), Rest}; -parse_ipv6([C |Rest], Acc) -> - parse_ipv6(Rest, [C |Acc]). - - -%%----------------------------------------------------------------- -%% Objectreference convertions -%%----------------------------------------------------------------- -object_to_string(Object) -> - iop_ior:string_code(Object). - -object_to_string(Object, [H|_] = Hosts) when is_list(H) -> - iop_ior:string_code(Object, Hosts); -object_to_string(_Object, _Hosts) -> - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). - -object_to_string(Object, [H|_] = Hosts, Port) when is_list(H) andalso - is_integer(Port) -> - iop_ior:string_code(Object, Hosts, Port); -object_to_string(_Object, _Hosts, _Port) -> - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). - -object_to_string(Object, [H|_] = Hosts, Port, SSLPort) when is_list(H) andalso - is_integer(Port) andalso - is_integer(SSLPort)-> - iop_ior:string_code(Object, Hosts, Port, SSLPort); -object_to_string(_Object, _Hosts, _Port, _SSLPort) -> - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). - - -string_to_object(IORString) -> - string_to_object(IORString, []). - -string_to_object(IORString, Ctx) when is_list(Ctx) -> - case lists:prefix("IOR", IORString) of - true -> - {ObjRef, _, _} = iop_ior:string_decode(IORString), - ObjRef; - _ -> - %% CORBA-2.4 allows both IOR and ior prefix. - case lists:prefix("ior", IORString) of - true -> - {ObjRef, _, _} = iop_ior:string_decode(IORString), - ObjRef; - _ -> - Data = orber_cosnaming_utils:select_type(IORString), - case orber_cosnaming_utils:lookup(Data, Ctx) of - String when is_list(String) -> - {Obj, _, _} = iop_ior:string_decode(String), - Obj; - ObjRef -> - ObjRef - end - end - end; -string_to_object(IORString, Ctx) -> - orber:dbg("[~p] corba:string_to_object(~p, ~p);~n" - "Failed to supply a context list.", - [?LINE, IORString, Ctx], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). - -%%------------------------------------------------------------ -%% -%% Implementation of NON-standard functions -%% -%%------------------------------------------------------------ -create(Module, TypeID) -> - create(Module, TypeID, []). - -create(Module, TypeID, Env) -> - common_create(Module, TypeID, Env, [], 'start'). - -create(Module, TypeID, Env, {Type, RegName}) -> - common_create(Module, TypeID, Env, [{regname, {Type, RegName}}], 'start'); -create(Module, TypeID, Env, Options) -> - common_create(Module, TypeID, Env, Options, 'start'). - - -create_link(Module, TypeID) -> - create_link(Module, TypeID, []). - -create_link(Module, TypeID, Env) -> - common_create(Module, TypeID, Env, [], 'start_link'). - -create_link(Module, TypeID, Env, {Type, RegName}) -> - common_create(Module, TypeID, Env, [{regname, {Type, RegName}}], 'start_link'); -create_link(Module, TypeID, Env, Options) -> - common_create(Module, TypeID, Env, Options, 'start_link'). - - -create_remote(Node, Module, TypeID) -> - create_remote(Node, Module, TypeID, []). - -create_remote(Node, Module, TypeID, Env) -> - common_create_remote(Node, Module, TypeID, Env, [], 'start'). - -create_remote(Node, Module, TypeID, Env, {Type, RegName}) -> - common_create_remote(Node, Module, TypeID, Env, [{regname, {Type, RegName}}], 'start'); -create_remote(Node, Module, TypeID, Env, Options) -> - common_create_remote(Node, Module, TypeID, Env, Options, 'start'). - - -create_link_remote(Node, Module, TypeID) -> - create_link_remote(Node, Module, TypeID, []). - -create_link_remote(Node, Module, TypeID, Env) -> - common_create_remote(Node, Module, TypeID, Env, [], 'start_link'). - -create_link_remote(Node, Module, TypeID, Env, {Type, RegName}) -> - common_create_remote(Node, Module, TypeID, Env, [{regname, {Type, RegName}}], 'start_link'); -create_link_remote(Node, Module, TypeID, Env, Options) -> - common_create_remote(Node, Module, TypeID, Env, Options, 'start_link'). - -common_create_remote(Node, Module, TypeID, Env, {Type, RegName}, StartMethod) -> - common_create_remote(Node, Module, TypeID, Env, [{regname, {Type, RegName}}], StartMethod); -common_create_remote(Node, Module, TypeID, Env, Options, StartMethod) -> - case node_check(Node) of - true -> - rpc:call(Node, corba, common_create, [Module, TypeID, Env, Options, StartMethod]); - _ -> - orber:dbg("[~p] corba:common_create_remote(~p);~n" - "Node not in current domain.", [?LINE, Node], ?DEBUG_LEVEL), - raise(#'OBJ_ADAPTER'{completion_status=?COMPLETED_NO}) - end. - -node_check(Node) -> - lists:member(Node,orber:orber_nodes()). - -common_create(Module, _TypeID, Env, Options, StartMethod) when is_list(Options) -> - Opt = evaluate_options(Options, #options{}), - case Opt#options.regname of - [] -> - ok; - {'local', Atom} when is_atom(Atom) andalso Opt#options.persistent == false -> - ok; - {'global', _} -> - ok; - Why -> - orber:dbg("[~p] corba:common_create(~p, ~p);~n" - "Bad name type or combination(~p).", - [?LINE, Module, Options, Why], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1), - completion_status=?COMPLETED_NO}) - end, - case Opt of - #options{pseudo = false, passive = false} -> - case gen_server:StartMethod(Module, {Opt#options.object_flags, Env}, - Opt#options.create_options) of - {ok, Pid} -> - case catch mk_objkey(Module, Pid, Opt#options.regname, - Opt#options.persistent, - Opt#options.object_flags) of - {'EXCEPTION', E} -> - %% This branch is only used if we couldn't register - %% our new objectkey due to an internal error in orber. - gen_server:call(Pid, stop), - raise(E); - {'EXIT', _} -> - %% This branch takes care of exit values - %% which aren't expected (due to bug). - gen_server:call(Pid, stop), - raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1), - completion_status=?COMPLETED_NO}); - Objkey when Opt#options.sup_child == true -> - {ok, Pid, Objkey}; - Objkey -> - Objkey - end; - X -> - X - end; - #options{pseudo = true, passive = false} -> - ModuleImpl = list_to_atom(lists:concat([Module, '_impl'])), - case ModuleImpl:init(Env) of - {ok, State} -> - create_subobject_key(mk_pseudo_objkey(Module, ModuleImpl, - Opt#options.object_flags), - State); - {ok, State,_} -> - create_subobject_key(mk_pseudo_objkey(Module, ModuleImpl, - Opt#options.object_flags), - State); - Reason -> - orber:dbg("[~p] corba:common_create(~p);~n" - "'init' function incorrect(~p).", - [?LINE, ModuleImpl, Reason], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1), - completion_status=?COMPLETED_NO}) - end; - #options{pseudo = false, passive = true} -> - ModuleImpl = list_to_atom(lists:concat([Module, '_impl'])), - create_subobject_key(mk_passive_objkey(Module, ModuleImpl, - Opt#options.object_flags), - ?groupid_to_table(Opt#options.group_id)); - What -> - orber:dbg("[~p] corba:common_create(~p, ~p);~n" - "not a boolean(~p).", - [?LINE, Module, Options, What], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{minor=(?ORBER_VMCID bor 1), - completion_status=?COMPLETED_NO}) - end. - -%%---------------------------------------------------------------------- -%% Function : dispose -%% Arguments : Object -%% Returns : -%% Description: Terminate the object represented by the supplied reference. -%%---------------------------------------------------------------------- -dispose(?ORBER_NIL_OBJREF) -> - ok; -dispose(Obj) -> - corba_boa:dispose(Obj). - -%%---------------------------------------------------------------------- -%% Function : create_nil_objref -%% Arguments : - -%% Returns : A NIL object reference -%% Description: -%%---------------------------------------------------------------------- -create_nil_objref() -> - ?ORBER_NIL_OBJREF. - -%%---------------------------------------------------------------------- -%% Function : create_subobject_key -%% Arguments : A local object reference and an Erlang term(). -%% Returns : A new instance of the supplied reference with the -%% sub-object field changed to the given value. -%% Description: Initially, this field is set to 'undefined' -%%---------------------------------------------------------------------- -create_subobject_key(Objkey, B) when is_binary(B) -> - iop_ior:set_privfield(Objkey, B); -create_subobject_key(Objkey, T) -> - create_subobject_key(Objkey, term_to_binary(T)). - -%%---------------------------------------------------------------------- -%% Function : get_subobject_key -%% Arguments : A local object reference -%% Returns : Erlang term(). -%% Description: Return the value set by using create_subobject_key/2 -%%---------------------------------------------------------------------- -get_subobject_key(Objkey) -> - iop_ior:get_privfield(Objkey). - -%%---------------------------------------------------------------------- -%% Function : get_pid -%% Arguments : A local object reference -%% Returns : If the object is local and is associated with a pid, this -%% pid is returned. Otherwise, external- or pseudo-object, -%% an exception is raised. -%% Description: -%%---------------------------------------------------------------------- -get_pid(Objkey) -> - case iop_ior:get_key(Objkey) of - {'internal', Key, _, _, _} -> - orber_objectkeys:get_pid(Key); - {'internal_registered', Key, _, _, _} when is_atom(Key) -> - case whereis(Key) of - undefined -> - raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}); - Pid -> - Pid - end; - R -> - orber:dbg("[~p] corba:get_pid(~p);~n" - "Probably a pseudo- or external object(~p).", - [?LINE, Objkey, R], ?DEBUG_LEVEL), - raise(#'INV_OBJREF'{completion_status=?COMPLETED_NO}) - end. - -%%---------------------------------------------------------------------- -%% Function : raise -%% Arguments : Local exception representation. -%% Returns : Throws the exception. -%% Description: -%%---------------------------------------------------------------------- -%% To avoid dialyzer warnings due to the use of exit/throw. --spec raise(term()) -> no_return(). -raise(E) -> - throw({'EXCEPTION', E}). - -%%---------------------------------------------------------------------- -%% Function : raise_with_state -%% Arguments : Local exception representation. -%% Returns : Throws the exception. -%% Description: -%%---------------------------------------------------------------------- -%% To avoid dialyzer warnings due to the use of exit/throw. --spec raise_with_state(term(), term()) -> no_return(). -raise_with_state(E, State) -> - throw({reply, {'EXCEPTION', E}, State}). - -%%---------------------------------------------------------------------- -%% Function : reply -%% Arguments : To - pid -%% Reply - Erlang term(). -%% Returns : -%% Description: Used to reply to the invoker but still be able -%% to do some more work in the callback module. -%%---------------------------------------------------------------------- -reply(To, Reply) -> - gen_server:reply(To, Reply). - -%%---------------------------------------------------------------------- -%% Function : print_object -%% Arguments : An object represented as one of the following: -%% - local (tuple) -%% - IOR -%% - stringified IOR -%% - corbaloc- or corbaname-schema -%% IoDevice - the same as the io-module defines. -%% Returns : -%% Description: Prints the object's components and profiles. -%%---------------------------------------------------------------------- -print_object(Object) -> - iop_ior:print(Object). -print_object(Object, IoDevice) -> - iop_ior:print(IoDevice, Object). - -%%---------------------------------------------------------------------- -%% Function : add_alternate_iiop_address -%% Arguments : Local object (tuple or IOR). -%% IP - IP-string -%% Port - integer(). -%% Returns : A local IOR with a TAG_ALTERNATE_IIOP_ADDRESS component. -%% Description: -%%---------------------------------------------------------------------- -add_alternate_iiop_address(Obj, Host, Port) when is_list(Host) andalso is_integer(Port) -> - TC = #'IOP_TaggedComponent'{tag = ?TAG_ALTERNATE_IIOP_ADDRESS, - component_data = #'ALTERNATE_IIOP_ADDRESS'{ - 'HostID' = Host, - 'Port' = Port}}, - iop_ior:add_component(Obj, TC); -add_alternate_iiop_address(_, Host, Port) -> - orber:dbg("[~p] corba:add_alternate_iiop_address(~p, ~p);~n" - "Incorrect argument(s). Host must be IP-string and Port an integer.", - [?LINE, Host, Port], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}). - - -%%---------------------------------------------------------------------- -%% Function : add_FTGroup_component -%% Arguments : Local object (tuple or IOR). -%% FTDomain - FT Domain. String(). -%% GroupID - Replicated object group's id. Integer(). (ulonglong) -%% GroupVer - Object group's version number. Integer(). (ulong) -%% Returns : A local IOR with one TAG_FT_GROUP component. -%% Description: -%%---------------------------------------------------------------------- -add_FTGroup_component(Obj, FTDomain, GroupID, GroupVer) - when is_list(FTDomain) andalso is_integer(GroupID) andalso is_integer(GroupVer) andalso - GroupID >= ?ULONGLONGMIN andalso GroupID =< ?ULONGLONGMAX andalso - GroupVer >= ?ULONGMIN andalso GroupVer =< ?ULONGMAX -> - TC = #'IOP_TaggedComponent'{tag = ?TAG_FT_GROUP, - component_data = #'FT_TagFTGroupTaggedComponent'{ - version = #'GIOP_Version'{major = 1, minor = 0}, - ft_domain_id = FTDomain, - object_group_id = GroupID, - object_group_ref_version = GroupVer}}, - iop_ior:add_component(Obj, TC); -add_FTGroup_component(_Obj, FTDomain, GroupID, GroupVer) -> - orber:dbg("[~p] corba:add_FTGroup_component(~p, ~p, ~p);~n" - "Incorrect argument(s).", - [?LINE, FTDomain, GroupID, GroupVer], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{completion_status = ?COMPLETED_NO}). - - -%%---------------------------------------------------------------------- -%% Function : add_FTPrimary_component -%% Arguments : Local object (tuple or IOR). -%% Returns : A local IOR with one TAG_FT_PRIMARY component. -%% Description: -%%---------------------------------------------------------------------- -add_FTPrimary_component(Obj) -> - TC = #'IOP_TaggedComponent'{ - tag=?TAG_FT_PRIMARY, - component_data=#'FT_TagFTPrimaryTaggedComponent'{primary = true}}, - iop_ior:add_component(Obj, TC). - - -%%----------------------------------------------------------------- -%% Generic functions for accessing the call-back modules (i.e. X_impl.erl). -%% These functions are invoked by the generated stubs. -%%----------------------------------------------------------------- -handle_init(M, {Flags, Env}) -> - case M:init(Env) of - {ok, State} -> - {ok, {#is{flags = Flags}, State}}; - {ok,State,Timeout} -> - {ok, {#is{flags = Flags}, State}, Timeout}; - Other -> - %% E.g. ignore | {stop, Reason} - Other - end. - - -handle_terminate(M, Reason, {_InternalState, State}) -> - catch (M:terminate(Reason, State)). - -handle_info(M, Info, {InternalState, State}) -> - case catch M:handle_info(Info, State) of - {noreply,NewState} -> - {noreply, {InternalState, NewState}}; - {noreply, NewState, Timeout} -> - {noreply, {InternalState, NewState}, Timeout}; - {stop, Reason, NewState} -> - {stop, Reason, {InternalState, NewState}}; - {'EXIT', Why} -> - handle_exit(InternalState, State, Why, true, - {M, handle_info}, [Info, State]) - end. - -handle_code_change(M, OldVsn, {InternalState, State}, Extra) -> - {ok, NewState} = M:code_change(OldVsn, State, Extra), - {ok, {InternalState, NewState}}. - - -%% This function handles call Pre- & Post-conditions. -handle_call(M, F, A, {InternalState, State}, Ctx, This, From, - PreData, PostData, Stub) -> - CArgs = call_state(A, State, This, From), - case catch invoke_precond(PreData, Stub, F, CArgs) of - {'EXIT', Why} -> - handle_exit(InternalState, State, Why, false, PreData, [Stub, F, CArgs]); - {'EXCEPTION', E} -> - {reply, {'EXCEPTION', E}, {InternalState, State}}; - ok -> - Result = handle_call2(M, F, CArgs, InternalState, State, Ctx), - case catch invoke_postcond(PostData, Stub, F, CArgs, Result) of - {'EXIT', Why} -> - handle_exit(InternalState, State, Why, false, PostData, A); - {'EXCEPTION', E} -> - {reply, {'EXCEPTION', E}, {InternalState, State}}; - ok -> - Result - end - end. - - -invoke_precond(false, _, _, _) -> - ok; -invoke_precond({CondM, CondF}, Stub, F, CArgs) -> - CondM:CondF(Stub, F, CArgs). - -%% We must remove the Internal State before invoking post-cond. -invoke_postcond(false, _, _, _, _) -> - ok; -invoke_postcond({CondM, CondF}, Stub, F, CArgs, {reply, Reply, {_, NS}}) -> - CondM:CondF(Stub, F, CArgs, {reply, Reply, NS}); -invoke_postcond({CondM, CondF}, Stub, F, CArgs, {reply, Reply, {_, NS}, Timeout}) -> - CondM:CondF(Stub, F, CArgs, {reply, Reply, NS, Timeout}); -invoke_postcond({CondM, CondF}, Stub, F, CArgs, {stop, Reason, Reply, {_, NS}}) -> - CondM:CondF(Stub, F, CArgs, {stop, Reason, Reply, NS}); -invoke_postcond({CondM, CondF}, Stub, F, CArgs, {stop, Reason, {_, NS}}) -> - CondM:CondF(Stub, F, CArgs, {stop, Reason, NS}); -invoke_postcond({CondM, CondF}, Stub, F, CArgs, {noreply,{_, NS}}) -> - CondM:CondF(Stub, F, CArgs, {noreply,NS}); -invoke_postcond({CondM, CondF}, Stub, F, CArgs, {noreply,{_, NS}, Timeout}) -> - CondM:CondF(Stub, F, CArgs, {noreply, NS, Timeout}); -invoke_postcond({CondM, CondF}, Stub, F, CArgs, Result) -> - CondM:CondF(Stub, F, CArgs, Result). - - -handle_call(M, F, A, {InternalState, State}, Ctx, This, From) -> - handle_call2(M, F, call_state(A, State, This, From), InternalState, State, Ctx). - -handle_call2(M, F, A, InternalState, State, []) -> - case catch apply(M, F, A) of - {reply, Reply, NewState} -> - {reply, add_context(Reply), {InternalState, NewState}}; - {reply, Reply, NewState, Timeout} -> - {reply, add_context(Reply), {InternalState, NewState}, Timeout}; - {stop, Reason, Reply, NewState} -> - {stop, Reason, add_context(Reply), {InternalState, NewState}}; - {stop, Reason, NewState} -> - {stop, Reason, {InternalState, NewState}}; - {noreply,NewState} -> - {noreply,{InternalState, NewState}}; - {noreply,NewState,Timeout} -> - {noreply,{InternalState, NewState},Timeout}; - {'EXIT', Reason} -> - handle_exit(InternalState, State, Reason, false, {M, F}, A); - {'EXCEPTION', E} -> - {reply, add_context({'EXCEPTION', E}), {InternalState, State}}; - {Reply, NewState} -> - {reply, add_context(Reply), {InternalState, NewState}} - end; -handle_call2(M, F, A, InternalState, State, Ctx) -> - %% Set the new Context. - put(oe_server_in_context, Ctx), - case catch apply(M, F, A) of - {reply, Reply, NewState} -> - put(oe_server_in_context, undefined), - {reply, add_context(Reply), {InternalState, NewState}}; - {reply, Reply, NewState, Timeout} -> - put(oe_server_in_context, undefined), - {reply, add_context(Reply), {InternalState, NewState}, Timeout}; - {stop, Reason, Reply, NewState} -> - {stop, Reason, add_context(Reply), {InternalState, NewState}}; - {stop, Reason, NewState} -> - {stop, Reason, {InternalState, NewState}}; - {noreply,NewState} -> - put(oe_server_in_context, undefined), - {noreply, {InternalState, NewState}}; - {noreply, {InternalState, NewState}, Timeout} -> - put(oe_server_in_context, undefined), - {noreply, {InternalState, NewState},Timeout}; - {'EXIT', Reason} -> - handle_exit(InternalState, State, Reason, false, {M, F}, A); - {'EXCEPTION', E} -> - put(oe_server_in_context, undefined), - {reply, add_context({'EXCEPTION', E}), {InternalState, State}}; - {Reply, NewState} -> - put(oe_server_in_context, undefined), - {reply, add_context(Reply), {InternalState, NewState}} - end. - -call_state(A, State, false, false) -> - [State|A]; -call_state(A, State, false, From) -> - [From, State|A]; -call_state(A, State, This, false) -> - [This, State|A]; -call_state(A, State, This, From) -> - [This, From, State|A]. - -cast_state(A, State, false) -> - [State|A]; -cast_state(A, State, This) -> - [This, State|A]. - -add_context(Reply) -> - %% Reset oe_server_out_context - case put(oe_server_out_context, undefined) of - undefined -> - Reply; - _OutCtx -> - %% The previous value wasn't 'undefined', which means that - %% the server supplied a return context. - Reply - end. - - -%% This function handles call Pre- & Post-conditions. -handle_cast(M, F, A, {InternalState, State}, Ctx, This, PreData, PostData, Stub) -> - CArgs = cast_state(A, State, This), - case catch invoke_precond(PreData, Stub, F, CArgs) of - {'EXIT', Why} -> - handle_exit(InternalState, State, Why, true, PreData, [Stub, F, CArgs]); - {'EXCEPTION', _} -> - {noreply, {InternalState, State}}; - ok -> - Result = handle_cast2(M, F, CArgs, InternalState, State, Ctx), - case catch invoke_postcond(PostData, Stub, F, CArgs, Result) of - {'EXIT', Why} -> - handle_exit(InternalState, State, Why, true, PostData, A); - {'EXCEPTION', _} -> - {noreply, {InternalState, State}}; - ok -> - Result - end - end. - - -handle_cast(M, F, A, {InternalState, State}, Ctx, This) -> - handle_cast2(M, F, cast_state(A, State, This), InternalState, State, Ctx). - -handle_cast2(M, F, A, InternalState, State, []) -> - case catch apply(M, F, A) of - {noreply, NewState} -> - {noreply, {InternalState, NewState}}; - {noreply, NewState, Timeout} -> - {noreply, {InternalState, NewState}, Timeout}; - {stop, Reason, NewState} -> - {stop, Reason, {InternalState, NewState}}; - {'EXCEPTION', _} -> - {noreply, {InternalState, State}}; - {'EXIT', Reason} -> - handle_exit(InternalState, State, Reason, true, {M, F}, A); - NewState -> - {noreply, {InternalState, NewState}} - end; -handle_cast2(M, F, A, InternalState, State, Ctx) -> - put(oe_server_in_context, Ctx), - case catch apply(M, F, A) of - {noreply, NewState} -> - put(oe_server_in_context, undefined), - {noreply, {InternalState, NewState}}; - {noreply, NewState, Timeout} -> - put(oe_server_in_context, undefined), - {noreply, {InternalState, NewState}, Timeout}; - {stop, Reason, NewState} -> - {stop, Reason, {InternalState, NewState}}; - {'EXCEPTION', _} -> - put(oe_server_in_context, undefined), - {noreply, {InternalState, State}}; - {'EXIT', Reason} -> - handle_exit(InternalState, State, Reason, true, {M, F}, A); - NewState -> - put(oe_server_in_context, undefined), - {noreply, {InternalState, NewState}} - end. - -handle_exit(InternalState, State, {undef, [{M, F, _, _}|_]} = Reason, - OnewayOp, {M, F}, A) -> - case catch check_exports(M:module_info(exports), F) of - {'EXIT',{undef,_}} -> - %% No such module. - orber:dbg("~p.beam doesn't exist.~n" - "Check IC compile options (e.g. 'impl') and that the~n" - "beam-file is load-able.", - [M], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 1), - completion_status=?COMPLETED_MAYBE}); - "" -> - orber:dbg("~p:~p/~p doesn't exist.~n" - "Check spelling, export-attributes etc", - [M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 2), - completion_status=?COMPLETED_MAYBE}); - Exports when is_list(Exports) -> - orber:dbg("~p:~p/~p doesn't exist.~n" - "~p:~p~s do exists.~nCheck export-attributes etc", - [M, F, length(A), M, F, Exports], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 3), - completion_status=?COMPLETED_MAYBE}); - _ -> - %% Should never happen - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}) - end; -handle_exit(InternalState, State, {undef, [{M2, F2, A2, _}|_]} = Reason, - OnewayOp, {M, F}, A) -> - case catch check_exports(M2:module_info(exports), F2) of - {'EXIT',{undef,_}} -> - %% No such module. - orber:dbg("~p.beam doesn't exist.~n" - "~p:~p/~p invoked an operation on the module above.~n" - "Check IC compile options and that the beam-file is load-able.", - [M2, M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 5), - completion_status=?COMPLETED_MAYBE}); - "" -> - orber:dbg("~p:~p/~p doesn't exist.~n" - "~p:~p/~p invoked the operation above~n" - "Check spelling, export-attributes etc", - [M2, F2, length(A2), M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 6), - completion_status=?COMPLETED_MAYBE}); - Exports when is_list(Exports) -> - orber:dbg("~p:~p/~p doesn't exist.~n" - "~p:~p~s do exist(s).~nCheck export-attributes etc~n" - "~p:~p/~p invoked the operation above~n", - [M2, F2, length(A2), M2, F2, Exports, M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 7), - completion_status=?COMPLETED_MAYBE}); - _ -> - %% Should never happen - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}) - end; -%% Misc errors. We separate between direct and in-direct errors. Due to different -%% notation we must separate between different cases. -handle_exit(InternalState, State, {{case_clause,_}, [{M, F, _}|_]} = Reason, - OnewayOp, {M, F}, A) -> - orber:dbg("~p:~p/~p contains a 'case_clause' error.", - [M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 8), - completion_status=?COMPLETED_MAYBE}); -handle_exit(InternalState, State, {Reason, [{M, F, _}|_]}, OnewayOp, {M, F}, A) -> - orber:dbg("~p:~p/~p contains a '~p' error.", - [M, F, length(A), Reason], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 8), - completion_status=?COMPLETED_MAYBE}); -handle_exit(InternalState, State, {function_clause, [{M2, F2, A2}|_]} = Reason, - OnewayOp, {M, F}, A) -> - orber:dbg("~p:~p/~p contains a 'function_clause' error.~n" - "Invoked via the operation:~n" - "~p:~p/~p", - [M2, F2, length(A2), M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 9), - completion_status=?COMPLETED_MAYBE}); -handle_exit(InternalState, State, {{case_clause,_}, [{M2, F2, A2}|_]} = Reason, - OnewayOp, {M, F}, A) -> - orber:dbg("~p:~p/~p contains a 'case_clause' error.~n" - "Invoked via the operation:~n" - "~p:~p/~p", - [M2, F2, A2, M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 9), - completion_status=?COMPLETED_MAYBE}); -handle_exit(InternalState, State, {Reason, [{M2, F2, A2}|_]} = Reason, - OnewayOp, {M, F}, A) -> - orber:dbg("~p:~p/~p contains a '~p' error.~n" - "Invoked via the operation:~n" - "~p:~p/~p", - [M2, F2, A2, Reason, M, F, length(A)], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 9), - completion_status=?COMPLETED_MAYBE}); -handle_exit(InternalState, State, Reason, OnewayOp, {M, F}, A) -> - orber:dbg("~p:~p(~p) ->~n" - " {EXIT, ~p}~n", - [M, F, A, Reason], ?DEBUG_LEVEL), - reply_after_exit(InternalState, State, Reason, OnewayOp, - #'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 10), - completion_status=?COMPLETED_MAYBE}). - - -reply_after_exit(#is{flags = Flags} = InternalState, State, - Reason, OnewayOp, Exc) -> - case ?ORB_FLAG_TEST(Flags, ?ORB_SURVIVE_EXIT) of - false -> - exit(Reason); - true when OnewayOp == false -> - put(oe_server_in_context, undefined), - {reply, {'EXCEPTION', Exc}, {InternalState, State}}; - true -> - %% One-way operation. Cannot return exception. - put(oe_server_in_context, undefined), - {noreply, {InternalState, State}} - end. - - -check_exports(Exports, Op) -> - check_exports(Exports, Op, []). - -check_exports([], _, Acc) -> - Acc; -check_exports([{Op, Arity}|Rest], Op, Acc) -> - check_exports(Rest, Op, Acc ++ "/" ++ integer_to_list(Arity)); -check_exports([_|Rest], Op, Acc) -> - check_exports(Rest, Op, Acc). - - -%%----------------------------------------------------------------- -%% Corba:call - the function for reqests -%%----------------------------------------------------------------- -call(Obj, Func, Args, TypesOrMod) -> - call_helper(Obj, Func, Args, TypesOrMod, infinity, []). - -call(Obj, Func, Args, TypesOrMod, [{context, Ctx}]) -> - call_helper(Obj, Func, Args, TypesOrMod, infinity, Ctx); -call(Obj, Func, Args, TypesOrMod, [{timeout, Timeout}]) -> - call_helper(Obj, Func, Args, TypesOrMod, Timeout, []); -call(Obj, Func, Args, TypesOrMod, Extra) when is_list(Extra) -> - ExtraData = extract_extra_data(Extra, #extra{}), - call_helper(Obj, Func, Args, TypesOrMod, ExtraData#extra.timeout, - ExtraData#extra.context); -call(Obj, Func, Args, TypesOrMod, Timeout) -> - call_helper(Obj, Func, Args, TypesOrMod, Timeout, []). - -call_helper(Obj, Func, Args, TypesOrMod, Timeout, InCtx) -> - Ctx = get_implicit_context(InCtx), - case iop_ior:get_key(Obj) of - {'internal', Key, _, Flags, Mod} -> - Pid = orber_objectkeys:get_pid(Key), - call_internal(Pid, Obj, Func, Args, TypesOrMod, - ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK), - ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Timeout, Ctx); - {'internal_registered', Key, _, Flags, Mod} -> - call_internal(Key, Obj, Func, Args, TypesOrMod, - ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK), - ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Timeout, Ctx); - {'external', Key} when is_atom(TypesOrMod) -> - case catch TypesOrMod:oe_tc(Func) of - {'EXIT', What} -> - orber:dbg("[~p] corba:call_helper(~p);~n" - "The call-back module does not exist or" - " incorrect IC-version used.~nReason: ~p", - [?LINE, TypesOrMod, What], ?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7), - completion_status=?COMPLETED_NO}); - undefined -> - raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4), - completion_status=?COMPLETED_NO}); - Types -> - orber_iiop:request(Key, Func, Args, Types, 'true', Timeout, Obj, Ctx) - end; - {'external', Key} -> - orber_iiop:request(Key, Func, Args, TypesOrMod, 'true', Timeout, Obj, Ctx) - end. - -get_implicit_context([]) -> - case get(oe_server_in_context) of - undefined -> - []; - ImplCtx -> - ImplCtx - end; -get_implicit_context(Ctx) -> - case get(oe_server_in_context) of - undefined -> - Ctx; - ImplCtx -> - %% Both defined. An explicit interface context overrides - %% an implicit. - case check_for_interface_ctx(Ctx) of - false -> - ImplCtx; - true -> - remove_interface_ctx(ImplCtx, Ctx) - end - end. - -check_for_interface_ctx([]) -> - false; -check_for_interface_ctx([#'IOP_ServiceContext' - {context_id=?ORBER_GENERIC_CTX_ID, - context_data = {interface, _I}}|_]) -> - true; -check_for_interface_ctx([_|T]) -> - check_for_interface_ctx(T). - -remove_interface_ctx([], Acc) -> - Acc; -remove_interface_ctx([#'IOP_ServiceContext' - {context_id=?ORBER_GENERIC_CTX_ID, - context_data = {interface, _I}}|T], Acc) -> - remove_interface_ctx(T, Acc); -remove_interface_ctx([H|T], Acc) -> - remove_interface_ctx(T, [H|Acc]). - - -extract_extra_data([], ED) -> - ED; -extract_extra_data([{context, Ctx}|T], ED) -> - extract_extra_data(T, ED#extra{context = Ctx}); -extract_extra_data([{timeout, Timeout}|T], ED) -> - extract_extra_data(T, ED#extra{timeout = Timeout}). - -call_internal(Pid, Obj, Func, Args, Types, Check, PI, Mod, Timeout, Ctx) - when is_pid(Pid) andalso node(Pid) == node() -> - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - case catch gen_server:call(Pid, {Obj, Ctx, Func, Args}, Timeout) of - {'EXCEPTION', E} -> - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}), - typecheck_reply(Check, {'EXCEPTION', E}, Mod, Func), - raise(E); - {'EXIT',{timeout, _}} -> - Exc = #'TIMEOUT'{completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - {'EXIT',R} -> - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~ncall exit(~p).", - [?LINE, Func, Args, Types, R], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_NO}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - Res -> - invoke_pi_reply(PI, Obj, Ctx, Func, Res), - typecheck_reply(Check, Res, Types, Func), - Res - end; -call_internal(Pid, Obj, Func, Args, Types, Check, PI, - _Mod, Timeout, Ctx) when is_pid(Pid) -> - typecheck_request(Check, Args, Types, Func), - case catch rpc:call(node(Pid), corba, call_relay, - [Pid, {Obj, Ctx, Func, Args}, Timeout]) of - {'EXCEPTION', E} -> - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}), - typecheck_reply(Check, {'EXCEPTION', E}, Types, Func), - raise(E); - {badrpc, {'EXIT',R}} -> - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~ncall exit(~p).", - [?LINE, Func, Args, Types, R], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 3), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - {badrpc,nodedown} -> - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~nNode ~p down.", - [?LINE, Func, Args, Types, node(Pid)], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 2), - completion_status=?COMPLETED_NO}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - {badrpc, Reason} -> - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~n" - "Unable to invoke operation due to: ~p", - [?LINE, Func, Args, Types, Reason], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 5), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - Res -> - invoke_pi_reply(PI, Obj, Ctx, Func, Res), - typecheck_reply(Check, Res, Types, Func), - Res - end; - -%% This case handles if the reference is created as a Pseudo object. -%% Just call apply/3. -call_internal({pseudo, Module}, Obj, Func, Args, Types, Check, PI, - _Mod, _Timeout, Ctx) -> - OldCtx = put(oe_server_in_context, Ctx), - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - State = binary_to_term(get_subobject_key(Obj)), - case catch apply(Module, Func, [Obj, State|Args]) of - {noreply, _} -> - put(oe_server_in_context, OldCtx), - ok; - {noreply, _, _} -> - put(oe_server_in_context, OldCtx), - ok; - {reply, Reply, _} -> - put(oe_server_in_context, OldCtx), - invoke_pi_reply(PI, Obj, Ctx, Func, Reply), - typecheck_reply(Check, Reply, Types, Func), - Reply; - {reply, Reply, _, _} -> - put(oe_server_in_context, OldCtx), - invoke_pi_reply(PI, Obj, Ctx, Func, Reply), - typecheck_reply(Check, Reply, Types, Func), - Reply; - {stop, _, Reply, _} -> - put(oe_server_in_context, OldCtx), - invoke_pi_reply(PI, Obj, Ctx, Func, Reply), - typecheck_reply(Check, Reply, Types, Func), - Reply; - {stop, _, _} -> - put(oe_server_in_context, OldCtx), - ok; - {'EXCEPTION', E} -> - put(oe_server_in_context, OldCtx), - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}), - typecheck_reply(Check, {'EXCEPTION', E}, Types, Func), - raise(E); - {'EXIT', What} -> - put(oe_server_in_context, OldCtx), - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~n" - "Pseudo object exit(~p).", - [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - Unknown -> - put(oe_server_in_context, OldCtx), - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p);~n" - "Pseudo object failed due to bad return value (~p).", - [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 6), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc) - end; -call_internal({passive, Module}, Obj, Func, Args, Types, Check, PI, - Mod, Timeout, Ctx) -> - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - GroupID = binary_to_term(get_subobject_key(Obj)), - Transaction = - fun() -> - ObjectGroup = read_object_group(GroupID), - call_primary_protected(ObjectGroup, Module, Obj, - Func, Args, GroupID, - get_FTRequestCtx(Ctx)) - end, - case mnesia:transaction(Transaction) of - {atomic, Reply} -> - %% this check should be inside transaction so that - %% failing typecheck_reply would result in transaction - %% abortion. Or not. call_internal(Registered...) does not - %% cancel the state transition even if the result isn't type compliant. - %% So, we do likewise. - typecheck_reply(Check, Reply, Mod, Func), - Reply; - {aborted, {not_primary, Primary, _}} -> - FTRequestCtx = mk_FTRequestCtx(10000000), - case rpc:call(Primary, corba, call_internal, - [{passive, Module}, Obj, Func, Args, - Types, Check, PI, Mod, Timeout, - [FTRequestCtx|Ctx]]) of - {badrpc, Reason} -> - orber:dbg("[~p] corba:call_passive(~p, ~p, ~p); ~n" - " badrpc(~p).", - [?LINE, Func, Args, Types, Reason],?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=0, - completion_status=?COMPLETED_MAYBE}); - %% one should keep trying request_duration_policy_value -time. - {'EXCEPTION', E} -> - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}), - raise(E); - Reply -> - %% is this typecheck_reply neccessary? The check is made - %% on the remote node... - invoke_pi_reply(PI, Obj, Ctx, Func, Reply), - typecheck_reply(Check, Reply, Mod, Func), - Reply - %% generate RetentionID's and call Primary node with flag that tells - %% the node not to escalate rpc call's to next node if the primary - %% has changed again. - %% raise({not_primary, Primary}); - end; - {aborted, {throw, {'EXCEPTION', E}}} -> - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}), - typecheck_reply(Check, {'EXCEPTION', E}, Mod, Func), - raise(E); - {aborted, {'EXIT', What}} -> - orber:dbg("[~p] corba:call_passive(~p, ~p, ~p); " ++ - "Passive object exit(~p).", - [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - {aborted, Unknown} -> - orber:dbg("[~p] corba:call_passive(~p, ~p, ~p); " ++ - "Passive object failed due to bad return value (~p).", - [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 6), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc) - end; -call_internal(Registered, Obj, Func, Args, Types, Check, PI, - _Mod, Timeout, Ctx) when is_atom(Registered)-> - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - case whereis(Registered) of - undefined -> - Exc = #'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - P -> - case catch gen_server:call(P, {Obj, Ctx, Func, Args}, Timeout) of - {'EXCEPTION', E} -> - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', E}), - typecheck_reply(Check, {'EXCEPTION', E}, Types, Func), - raise(E); - {'EXIT',{timeout, _}} -> - Exc = #'TIMEOUT'{completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - {'EXIT',R} -> - orber:dbg("[~p] corba:call_internal(~p, ~p, ~p).~n" - "call exit(~p).", - [?LINE, Func, Args, Types, R], ?DEBUG_LEVEL), - Exc = #'TRANSIENT'{minor=(?ORBER_VMCID bor 5), - completion_status=?COMPLETED_MAYBE}, - invoke_pi_reply(PI, Obj, Ctx, Func, {'EXCEPTION', Exc}), - raise(Exc); - Res -> - invoke_pi_reply(PI, Obj, Ctx, Func, Res), - typecheck_reply(Check, Res, Types, Func), - Res - end - end. - -invoke_pi_request(false, _Obj, _Ctx, _Func, _Args) -> - ok; -invoke_pi_request(_, Obj, Ctx, Func, Args) -> - case orber:get_cached_interceptors() of - {native, PIs} -> - orber_pi:out_request(PIs, Obj, Ctx, Func, "localhost", Args); - _ -> - ok - end. - -invoke_pi_reply(false, _Obj, _Ctx, _Func, _Res) -> - ok; -invoke_pi_reply(_, Obj, Ctx, Func, Res) -> - case orber:get_cached_interceptors() of - {native, PIs} -> - orber_pi:in_reply(PIs, Obj, Ctx, Func, "localhost", Res); - _ -> - ok - end. - -typecheck_request(false, _, _, _) -> - ok; -typecheck_request(true, Args, Mod, Func) when is_atom(Mod) -> - case catch Mod:oe_tc(Func) of - undefined -> - raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4), - completion_status=?COMPLETED_NO}); - {'EXIT', What} -> - orber:dbg("[~p] corba:typecheck_request(~p, ~p, ~p);~n" - "The call-back module does not exist or incorrect" - "IC-version used.~nReason: ~p", - [?LINE, Mod, Func, Args, What], ?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7), - completion_status=?COMPLETED_NO}); - Types -> - typecheck_request_helper(Types, Args, Mod, Func) - end; -typecheck_request(true, Args, Types, Func) -> - typecheck_request_helper(Types, Args, Types, Func). - -typecheck_request_helper(Types, Args, Mod, Func) -> - case catch cdr_encode:validate_request_body( - #giop_env{version = {1,2}, tc = Types, parameters = Args, - host = orber:host(), iiop_port = orber:iiop_port(), - iiop_ssl_port = orber:iiop_ssl_port(), - domain = orber:domain(), - partial_security = orber:partial_security(), - flags = orber:get_flags()}) of - {'EXCEPTION', E} -> - {_, TC, _} = Types, - error_logger:error_msg("========= Orber Typecheck Request =========~n" - "Invoked......: ~p:~p/~p~n" - "Typecode.....: ~p~n" - "Arguments....: ~p~n" - "Result.......: ~p~n" - "===========================================~n", - [Mod, Func, length(TC), TC, Args, {'EXCEPTION', E}]), - raise(E); - {'EXIT',R} -> - {_, TC, _} = Types, - error_logger:error_msg("========= Orber Typecheck Request =========~n" - "Invoked......: ~p:~p/~p~n" - "Typecode.....: ~p~n" - "Arguments....: ~p~n" - "Result.......: ~p~n" - "===========================================~n", - [Mod, Func, length(TC), TC, Args, {'EXIT',R}]), - raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}); - _ -> - ok - end. - -typecheck_reply(true, Args, Mod, Func) when is_atom(Mod) -> - case catch Mod:oe_tc(Func) of - undefined -> - raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4), - completion_status=?COMPLETED_NO}); - {'EXIT', What} -> - orber:dbg("[~p] corba:typecheck_reply(~p, ~p, ~p);~n" - "The call-back module does not exist or incorrect" - " IC-version used.~nReason: ~p", - [?LINE, Mod, Func, Args, What], ?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7), - completion_status=?COMPLETED_NO}); - Types -> - typecheck_reply_helper(Types, Args, Mod, Func) - end; -typecheck_reply(true, Args, Types, Func) -> - typecheck_reply_helper(Types, Args, Types, Func); -typecheck_reply(_, _, _, _) -> - ok. - -typecheck_reply_helper(Types, Args, Mod, Func) -> - case catch cdr_encode:validate_reply_body( - #giop_env{version = {1,2}, tc = Types, - host = orber:host(), iiop_port = orber:iiop_port(), - iiop_ssl_port = orber:iiop_ssl_port(), - domain = orber:domain(), - partial_security = orber:partial_security(), - flags = orber:get_flags()}, Args) of - {'tk_except', ExcType, ExcTC, {'EXCEPTION', E}} -> - {_, TC, _} = Types, - error_logger:error_msg("========== Orber Typecheck Reply ==========~n" - "Invoked........: ~p:~p/~p~n" - "Exception Type.: ~p~n" - "Typecode.......: ~p~n" - "Raised.........: ~p~n" - "Result.........: ~p~n" - "===========================================~n", - [Mod, Func, length(TC), ExcType, ExcTC, Args, {'EXCEPTION', E}]), - raise(E); - {'EXCEPTION', E} -> - {RetType, TC, OutParams} = Types, - error_logger:error_msg("========== Orber Typecheck Reply ==========~n" - "Invoked......: ~p:~p/~p~n" - "Typecode.....: ~p~n" - "Reply........: ~p~n" - "Result.......: ~p~n" - "===========================================~n", - [Mod, Func, length(TC), [RetType | OutParams], Args, {'EXCEPTION', E}]), - raise(E); - {'tk_except', ExcType, ExcTC, {'EXIT',R}} -> - {_, TC, _} = Types, - error_logger:error_msg("========== Orber Typecheck Reply ==========~n" - "Invoked........: ~p:~p/~p~n" - "Exception Type.: ~p~n" - "Typecode.......: ~p~n" - "Raised.........: ~p~n" - "Result.........: ~p~n" - "===========================================~n", - [Mod, Func, length(TC), ExcType, ExcTC, Args, {'EXIT',R}]), - raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}); - {'EXIT',R} -> - {RetType, TC, OutParams} = Types, - error_logger:error_msg("========== Orber Typecheck Reply ==========~n" - "Invoked........: ~p:~p/~p~n" - "Typecode.......: ~p~n" - "Reply..........: ~p~n" - "Result.........: ~p~n" - "===========================================~n", - [Mod, Func, length(TC), [RetType | OutParams], Args, {'EXIT',R}]), - raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}); - _ -> - ok - end. - -call_relay(Pid, Data, Timeout) -> - case whereis(orber_objkeyserver) of - undefined -> - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 1), completion_status=?COMPLETED_MAYBE}); - _ -> - case catch gen_server:call(Pid, Data, Timeout) of - {'EXCEPTION', E} -> - raise(E); - {'EXIT',{timeout, _}} -> - raise(#'TIMEOUT'{completion_status=?COMPLETED_MAYBE}); - {'EXIT',R} -> - orber:dbg("[~p] corba:call_internal(~p);~n" - "call exit(~p).", [?LINE, Data, R], ?DEBUG_LEVEL), - exit(R); - Res -> - Res - end - end. - -%%----------------------------------------------------------------- -%% Corba:cast - the function for ONEWAY requests -%%----------------------------------------------------------------- -cast(Obj, Func, Args, TypesOrMod) -> - cast_helper(Obj, Func, Args, TypesOrMod, []). - -cast(Obj, Func, Args, TypesOrMod, [{context, Ctx}]) -> - cast_helper(Obj, Func, Args, TypesOrMod, Ctx). - -cast_helper(Obj, Func, Args, TypesOrMod, InCtx) -> - Ctx = get_implicit_context(InCtx), - case iop_ior:get_key(Obj) of - {'internal', Key, _, Flags, Mod} -> - Pid = orber_objectkeys:get_pid(Key), - cast_internal(Pid, Obj, Func, Args, TypesOrMod, - ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK), - ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Ctx); - {'internal_registered', Key, _, Flags, Mod} -> - cast_internal(Key, Obj, Func, Args, TypesOrMod, - ?ORB_FLAG_TEST(Flags, ?ORB_TYPECHECK), - ?ORB_FLAG_TEST(Flags, ?ORB_USE_PI), Mod, Ctx); - {'external', Key} when is_atom(TypesOrMod) -> - case catch TypesOrMod:oe_tc(Func) of - {'EXIT', What} -> - orber:dbg("[~p] corba:cast_helper(~p);~n" - "The call-back module does not exist or incorrect" - " IC-version used.~nReason: ~p", - [?LINE, TypesOrMod, What], ?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 7), - completion_status=?COMPLETED_NO}); - undefined -> - raise(#'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4), - completion_status=?COMPLETED_NO}); - Types -> - orber_iiop:request(Key, Func, Args, Types, 'false', infinity, - Obj, Ctx) - end; - {'external', Key} -> - orber_iiop:request(Key, Func, Args, TypesOrMod, 'false', infinity, - Obj, Ctx) - end. - -cast_internal(Pid, Obj, Func, Args, Types, Check, PI, _Mod, Ctx) - when is_pid(Pid) andalso node(Pid) == node() -> - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - catch gen_server:cast(Pid, {Obj, Ctx, Func, Args}), - ok; -cast_internal(Pid, Obj, Func, Args, Types, Check, PI, Mod, Ctx) when is_pid(Pid) -> - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - case catch rpc:call(node(Pid), corba, cast_relay, [Pid, {Obj, Ctx, Func, Args}]) of - {'EXCEPTION', E} -> - typecheck_reply(Check, {'EXCEPTION', E}, Mod, Func), - raise(E); - {badrpc, {'EXIT', _R}} -> - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 3), - completion_status=?COMPLETED_MAYBE}); - {badrpc,nodedown} -> - orber:dbg("[~p] corba:cast_internal(~p, ~p, ~p);~nNode ~p down.", - [?LINE, Func, Args, Types, node(Pid)], ?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 2), - completion_status=?COMPLETED_NO}); - Other -> - orber:dbg("[~p] corba:cast_internal(~p, ~p, ~p);~n" - "Communication with node: ~p failed with reason: ~p.", - [?LINE, Func, Args, Types, node(Pid), Other], ?DEBUG_LEVEL), - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 5), - completion_status=?COMPLETED_MAYBE}) - end; - -%% This case handles if the reference is created as a Pseudo object. -%% Just call apply/3. -cast_internal({pseudo, Module}, Obj, Func, Args, Types, Check, PI, _Mod, Ctx) -> - OldCtx = put(oe_server_in_context, Ctx), - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - State = binary_to_term(get_subobject_key(Obj)), - catch apply(Module, Func, [Obj, State|Args]), - put(oe_server_in_context, OldCtx), - ok; -cast_internal(Registered, Obj, Func, Args, Types, Check, PI, _Mod, Ctx) -> - invoke_pi_request(PI, Obj, Ctx, Func, Args), - typecheck_request(Check, Args, Types, Func), - case whereis(Registered) of - undefined -> - raise(#'OBJECT_NOT_EXIST'{completion_status=?COMPLETED_NO}); - P -> - gen_server:cast(P, {Obj, Ctx, Func, Args}) - end. - -cast_relay(Pid, Data) -> - case whereis(orber_objkeyserver) of - undefined -> - raise(#'TRANSIENT'{minor=(?ORBER_VMCID bor 1), - completion_status=?COMPLETED_NO}); - _ -> - gen_server:cast(Pid, Data) - end. - -%%----------------------------------------------------------------- -%% Corba:locate - this function is for the moment just used for tests -%%----------------------------------------------------------------- -locate(Obj) -> - locate(Obj, infinity, []). - -locate(Obj, Timeout) -> - locate(Obj, Timeout, []). - -locate(Obj, Timeout, Ctx) -> - case iop_ior:get_key(Obj) of - {'external', Key} -> - orber_iiop:locate(Key, Timeout, Obj, Ctx); - _ -> - orber_objectkeys:check(iop_ior:get_objkey(Obj)) - end. - -%%----------------------------------------------------------------- -%% Incomming request from iiop -%%----------------------------------------------------------------- -%% Operations which do not allow object invokation. -request_from_iiop(Obj, '_is_a', [Args], _, _, _) -> - catch corba_object:is_a(Obj, Args); -%% First the OMG specified this operation to be '_not_existent' and then -%% changed it to '_non_existent' without suggesting that both must be supported. -%% See CORBA2.3.1 page 15-34, Minor revision 2.3.1: October 1999 -request_from_iiop(Obj, '_not_existent', _, _, _, _) -> - catch corba_object:non_existent(Obj); -request_from_iiop(Obj, '_non_existent', _, _, _, _) -> - catch corba_object:non_existent(Obj); -request_from_iiop(_, '_FT_HB', _, _, _, _) -> - ok; - -%% "Ordinary" operations. -request_from_iiop({Mod, _, _, _, _, _}, oe_get_interface, - _, _, _, _ServiceCtx) when is_atom(Mod) -> - case catch Mod:oe_get_interface() of - {'EXIT', What} -> - orber:dbg("[~p] corba:request_from_iiop(~p);~n" - "The call-back module does not exist or" - " incorrect IC-version used.~nReason: ~p", - [?LINE, Mod, What], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 7), - completion_status=?COMPLETED_NO}}; - undefined -> - {'EXCEPTION', #'BAD_OPERATION'{minor = (?ORBER_VMCID bor 4), - completion_status='COMPLETED_NO'}}; - Interface -> - Interface - end; -request_from_iiop({_Mod, pseudo, Module, _UserDef, _OrberDef, _Flags} = ObjRef, - Func, Args, Types, ResponseExpected, _ServiceCtx) -> - State = binary_to_term(get_subobject_key(ObjRef)), - case ResponseExpected of - true -> - case catch apply(Module, Func, [ObjRef, State|Args]) of - {noreply, _} -> - ok; - {noreply, _, _} -> - ok; - {reply, Reply, _} -> - Reply; - {reply, Reply, _, _} -> - Reply; - {stop, _, Reply, _} -> - Reply; - {stop, _, _} -> - ok; - {'EXCEPTION', E} -> - {'EXCEPTION', E}; - {'EXIT', {undef, _}} -> - orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n" - "The call-back module does not exist.", - [?LINE, Func, Args, Types], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_NO}}; - {'EXIT', What} -> - orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n" - "Pseudo object exit(~p).~n" - "The call-back module probably contain an error.", - [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}}; - Unknown -> - orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n" - "Pseudo object failed(~p);~n" - "Confirm that the return value is correct" - " (e.g. {reply, Reply, State})", - [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 6), - completion_status=?COMPLETED_MAYBE}} - end; - false -> - catch apply(Module, Func, [ObjRef, State|Args]), - ok; - true_oneway -> - catch apply(Module, Func, [ObjRef, State|Args]), - ok - end; -% FOR PASSIVE REPLICATION! (Response IS expected --- one way semantics doesn't -% really mix with intentions to be consistent & fault tolerant.) -request_from_iiop({_Mod, passive, Module, _UserDef, _OrberDef, _Flags} = ObjRef, - Func, Args, Types, true, Ctx) -> - GroupID = binary_to_term(get_subobject_key(ObjRef)), - FTGroupVersionCtx = get_FTGroupVersionCtx(Ctx), - Transaction = - fun() -> - ObjectGroup = read_object_group(GroupID), - check_version_context(ObjectGroup, - FTGroupVersionCtx), - call_primary_protected(ObjectGroup, - Module, - ObjRef, - Func, - Args, - GroupID, - get_FTRequestCtx(Ctx)) - end, - case mnesia:transaction(Transaction) of - {atomic, Reply} -> - Reply; - {aborted, {too_old_reference, IOGR}} -> - {oe_location_forward_perm, IOGR}; - {aborted, {not_primary, _Primary, IOGR}} -> - case FTGroupVersionCtx of - [] -> - {oe_location_forward_perm, IOGR}; - _ -> - {'EXCEPTION', #'TRANSIENT'{minor = 0, - completion_status = ?COMPLETED_NO}} - end; - {aborted, {throw, {'EXCEPTION', E}}} -> - {'EXCEPTION', E}; - {aborted, {'EXIT', What}} -> - orber:dbg("[~p] corba:call_passive(~p, ~p, ~p);~n" - "Passive object exit(~p).", - [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor = 0, - completion_status=?COMPLETED_MAYBE}}; - {aborted, Unknown} -> - orber:dbg("[~p] corba:call_passive(~p, ~p, ~p);~n" - "Passive object failed due to bad return value (~p).", - [?LINE, Func, Args, Types, Unknown], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor = 0, - completion_status=?COMPLETED_MAYBE}} - end; -request_from_iiop({_Mod, _Type, Key, _UserDef, _OrberDef, _Flags} = ObjRef, - Func, Args, Types, true, _ServiceCtx) -> - case catch gen_server:call(convert_key_to_pid(Key), - {ObjRef, [], Func, Args}, infinity) of - {'EXIT', What} -> - orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n" - "gen_server:call exit: ~p", - [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}}; - Result -> - Result - end; -request_from_iiop({_Mod, _Type, Key, _UserDef, _OrberDef, _Flags} = ObjRef, - Func, Args, Types, _, _ServiceCtx) -> - case catch gen_server:cast(convert_key_to_pid(Key), - {ObjRef, [], Func, Args}) of - {'EXIT', What} -> - orber:dbg("[~p] corba:request_from_iiop(~p, ~p, ~p);~n" - "gen_server:cast exit: ~p", - [?LINE, Func, Args, Types, What], ?DEBUG_LEVEL), - {'EXCEPTION', #'TRANSIENT'{minor=(?ORBER_VMCID bor 4), - completion_status=?COMPLETED_MAYBE}}; - Result -> - Result - end. - -%%------------------------------------------------------------ -%% Internal stuff -%%------------------------------------------------------------ - -convert_key_to_pid(Key) when is_binary(Key) -> - orber_objectkeys:get_pid(Key); -convert_key_to_pid(Name) when is_atom(Name) -> - Name. - -mk_objkey(Mod, Pid, RegName, Persistent) -> - mk_objkey(Mod, Pid, RegName, Persistent, 0). - -mk_objkey(Mod, Pid, [], _, Flags) when is_pid(Pid) -> - Key = make_objkey(), - case orber_objectkeys:register(Key, Pid, false) of - ok -> - {Mod, 'key', Key, term_to_binary(undefined), 0, Flags}; - R -> - orber:dbg("[~p] corba:mk_objkey(~p);~n" - "unable to store key(~p).", [?LINE, Mod, R], ?DEBUG_LEVEL), - raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}) - end; -mk_objkey(Mod, Pid, {'global', RegName}, Persitent, Flags) when is_pid(Pid) -> - Key = term_to_binary(RegName), - case orber_objectkeys:register(Key, Pid, Persitent) of - ok -> - {Mod, 'key', Key, term_to_binary(undefined), 0, Flags}; - R -> - orber:dbg("[~p] corba:mk_objkey(~p, ~p);~n" - "unable to store key(~p).", - [?LINE, Mod, RegName, R], ?DEBUG_LEVEL), - raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}) - end; -mk_objkey(Mod, Pid, {'local', RegName}, Persistent, Flags) when is_pid(Pid) andalso is_atom(RegName) -> - register(RegName, Pid), - Key = make_objkey(), - case orber_objectkeys:register(Key, Pid, Persistent) of - ok -> - {Mod, 'registered', RegName, term_to_binary(undefined), 0, Flags}; - R -> - orber:dbg("[~p] corba:mk_objkey(~p, ~p);~n" - "unable to store key(~p).", - [?LINE, Mod, RegName, R], ?DEBUG_LEVEL), - raise(#'INTERNAL'{minor=(?ORBER_VMCID bor 2), completion_status=?COMPLETED_NO}) - end. - - -mk_light_objkey(Mod, RegName) -> - {Mod, 'registered', RegName, term_to_binary(undefined), 0, 0}. - -mk_pseudo_objkey(Mod, Module, Flags) -> - {Mod, 'pseudo', Module, term_to_binary(undefined), 0, Flags}. - -mk_passive_objkey(Mod, Module, Flags) -> - {Mod, 'passive', Module, term_to_binary(undefined), 0, Flags}. - -make_objkey() -> - term_to_binary({{erlang:system_time(), - erlang:unique_integer()}, - node()}). - -objkey_to_string({_Mod, 'registered', 'orber_init', _UserDef, _OrberDef, _Flags}) -> - "INIT"; -objkey_to_string({Mod, Type, Key, UserDef, OrberDef, Flags}) -> - orber:domain() ++ [ 7 | binary_to_list(term_to_binary({Mod, Type, Key, UserDef, OrberDef, Flags}))]; -objkey_to_string(External_object_key) -> - External_object_key. - -string_to_objkey("INIT") -> - {orber_initial_references, 'registered', 'orber_init', term_to_binary(undefined), 0, 0}; -string_to_objkey(String) -> - case prefix(orber:domain(), String) of - [7 | Rest] -> - binary_to_term(list_to_binary(Rest)); - _ -> - String - end. -%% This function may only be used when we know it's a local reference (i.e. target -%% key in a request; IOR's passed as argument or reply doesn't qualify)! -string_to_objkey_local("INIT") -> - {orber_initial_references, 'registered', 'orber_init', term_to_binary(undefined), 0, 0}; -string_to_objkey_local(String) -> - case prefix(orber:domain(), String) of - [7 | Rest] -> - binary_to_term(list_to_binary(Rest)); - _ -> - case resolve_initial_references(String) of - ?ORBER_NIL_OBJREF -> - orber:dbg("[~p] corba:string_to_objkey_local(~p);~n" - "Invalid ObjektKey.", [?LINE, String], ?DEBUG_LEVEL), - ?ORBER_NIL_OBJREF; - Object -> - {location_forward, Object} - end - end. - -prefix([], L2) -> - L2; -prefix([E |L1], [E | L2]) -> - prefix(L1, L2); -prefix(_, _) -> - false. - - -evaluate_options([], Options) -> - GlobalFlags = orber:get_flags(), - Options2 = check_flag(Options, ?ORB_TYPECHECK, - ?ORB_ENV_LOCAL_TYPECHECKING, GlobalFlags), - Options3 = check_flag(Options2, ?ORB_USE_PI, ?ORB_ENV_USE_PI, GlobalFlags), - check_flag(Options3, ?ORB_SURVIVE_EXIT, ?ORB_ENV_SURVIVE_EXIT, GlobalFlags); -%% Pseudo or not. -evaluate_options([{pseudo, false}|Rest], Options) -> - evaluate_options(Rest, Options); -evaluate_options([{pseudo, true}|Rest], #options{passive = false} = Options) -> - evaluate_options(Rest, Options#options{pseudo = true}); -%% FT stuff -evaluate_options([{passive, true}|Rest], #options{pseudo = false} = Options) -> - evaluate_options(Rest, Options#options{passive = true}); -evaluate_options([{group_id, ID}|Rest], Options) when is_integer(ID) -> - evaluate_options(Rest, Options#options{group_id = ID}); -%% Options accepted by gen_server (e.g. dbg). -evaluate_options([{create_options, COpt}|Rest], Options) when is_list(COpt) -> - evaluate_options(Rest, Options#options{create_options = COpt}); -%% When starting object as supervisor child. -evaluate_options([{sup_child, false}|Rest], Options) -> - evaluate_options(Rest, Options); -evaluate_options([{sup_child, true}|Rest], Options) -> - evaluate_options(Rest, Options#options{sup_child = true}); -%% Persistent object-key -evaluate_options([{persistent, false}|Rest], Options) -> - evaluate_options(Rest, Options); -evaluate_options([{persistent, true}|Rest], Options) -> - evaluate_options(Rest, Options#options{persistent = true}); -evaluate_options([{regname, []}|Rest], Options) -> - evaluate_options(Rest, Options); -evaluate_options([{regname, Name}|Rest], Options) -> - evaluate_options(Rest, Options#options{regname = Name}); -evaluate_options([{survive_exit, false}|Rest], - #options{object_flags_set = FlagsSet} = Options) -> - %% This option overrides a global setting. - evaluate_options(Rest, Options#options{object_flags_set = - (?ORB_SURVIVE_EXIT bor FlagsSet)}); -evaluate_options([{survive_exit, true}|Rest], - #options{object_flags = Flags, - object_flags_set = FlagsSet} = Options) -> - evaluate_options(Rest, Options#options{object_flags = - (?ORB_SURVIVE_EXIT bor Flags), - object_flags_set = - (?ORB_SURVIVE_EXIT bor FlagsSet)}); -evaluate_options([{local_typecheck, false}|Rest], - #options{object_flags_set = FlagsSet} = Options) -> - %% This option overrides a global setting. - evaluate_options(Rest, Options#options{object_flags_set = - (?ORB_TYPECHECK bor FlagsSet)}); -evaluate_options([{local_typecheck, true}|Rest], - #options{object_flags = Flags, - object_flags_set = FlagsSet} = Options) -> - evaluate_options(Rest, Options#options{object_flags = (?ORB_TYPECHECK bor Flags), - object_flags_set = - (?ORB_TYPECHECK bor FlagsSet)}); -evaluate_options([{local_interceptors, false}|Rest], - #options{object_flags_set = FlagsSet} = Options) -> - %% This option overrides a global setting. - evaluate_options(Rest, Options#options{object_flags_set = - (?ORB_USE_PI bor FlagsSet)}); -evaluate_options([{local_interceptors, true}|Rest], - #options{object_flags = Flags, - object_flags_set = FlagsSet} = Options) -> - evaluate_options(Rest, Options#options{object_flags = (?ORB_USE_PI bor Flags), - object_flags_set = - (?ORB_USE_PI bor FlagsSet)}); -%% Temporary option. -evaluate_options([{no_security, true}|Rest], - #options{object_flags = Flags} = Options) -> - %% We do not allow this option to be set globally. - evaluate_options(Rest, Options#options{object_flags = (?ORB_NO_SECURITY bor Flags)}); -evaluate_options([{no_security, false}|Rest], Options) -> - %% We do not allow this option to be set globally. - evaluate_options(Rest, Options); -evaluate_options([{Key, Value}|_], _) -> - orber:dbg("[~p] corba:evaluate_options(~p, ~p);~n" - "Option not recognized, illegal value or combination.~n" - "Allowed settings:~n" - "survive_exit.......: boolean()~n" - "sup_child..........: boolean()~n" - "persistent.........: boolean()~n" - "pseudo.............: boolean()~n" - "local_typecheck....: boolean()~n" - "local_interceptors.: boolean()~n" - "regname............: {local, atom()} | {global, term()}", - [?LINE, Key, Value], ?DEBUG_LEVEL), - raise(#'BAD_PARAM'{completion_status=?COMPLETED_NO}). - -check_flag(#options{object_flags = Flags, - object_flags_set = FlagsSet} = Options, Flag, - FlagConstant, GlobalFlags) -> - %% Option activated/deactived by a supplied option. - case ?ORB_FLAG_TEST(FlagsSet, Flag) of - true -> - Options; - false -> - %% Not the above. Globally defined? - case ?ORB_FLAG_TEST(GlobalFlags, FlagConstant) of - true -> - Options#options{object_flags = (Flag bor Flags)}; - false -> - Options - end - end. - -%%%%%%%%%%%%%%%%% FOR PASSIVE REPLICATION! -% Note should be called inside transaction. Does not catch exceptions. -% let's not allow corba:reply from transaction... (no {noreply, ...} messages) -% should the object be able to stop itself by returning {stop, ...}? -% how about corba:dispose then? Deleting table representing object group and -% corresponding entry in ft_replication_manager -table might just do the job? -% No {stop, ...} messages for now -% Exceptions falls through. They are expected to be caught by transaction in a -% form of {aborted, {throw, {'EXCEPTION', ...}}} -call_passive(Module, Obj, Func, Args, GroupID) -> - [Record] = mnesia:read(ft_replicated_object, GroupID, sticky_write), - State = Record#ft_replicated_object.state, - - case apply(Module, Func, [Obj, State|Args]) of - {reply, Reply, NewState} -> - {Reply, NewState}; - {reply, Reply, NewState, _} -> - {Reply, NewState} - end, - mnesia:write(ft_replicated_object, - #ft_replicated_object{group_id = GroupID, state = NewState}, - sticky_write), - Reply. - - - -% FTRequestCtx protected object call -% One should protect agains aged reply. If expirations_time is reached and -% request is retransmitted, one might return BAD_CONTEXT -exception! -call_RQprotected(Module, Obj, Func, Args, GroupID, RQCtx) -> - case mnesia:read(ft_reply_retention, RQCtx, sticky_write) of - % fresh request - [] -> - Reply = call_passive(Module, Obj, Func, Args, GroupID), - mnesia:write(ft_reply_retention, - #ft_reply_retention{retention_id= RQCtx,reply= Reply}, - sticky_write), - Reply; - % retransmitted request - [#ft_reply_retention{reply = Reply}] -> - Reply - end. - - - -% call_primary_protected. Protects agains calling non-primary node. -% normal case, without FTRequest Service Context -call_primary_protected(#ft_replication_manager{primary = Primary}, - Module, - Obj, - Func, - Args, - GroupID, - []) when Primary == node() -> - call_passive(Module, Obj, Func, Args, GroupID); -% normal case, with FTRequest Service Context -call_primary_protected(#ft_replication_manager{primary = Primary}, - Module, - Obj, - Func, - Args, - GroupID, - RetentionID) when Primary == node() -> - call_RQprotected(Module, Obj, Func, Args, GroupID, RetentionID); -% case where primary resides in another node -call_primary_protected(#ft_replication_manager{primary = Primary, - iogr = IOGR}, - _Module, _Obj, _Func, _Args, _GroupID, _) -> - mnesia:abort({not_primary, Primary, IOGR}). - - - -% no context -check_version_context(_, []) -> - ok; -% client's IOGR is current. -check_version_context(#ft_replication_manager{ref_version = CurrentVer}, - GroupVer) when CurrentVer == GroupVer -> - ok; -% client's IOGR is old. -check_version_context(#ft_replication_manager{ref_version = CurrentVer, - iogr = IOGR}, - GroupVer) when CurrentVer > GroupVer -> - mnesia:abort({too_old_reference, IOGR}); -% client's IOGR is too new! -check_version_context(#ft_replication_manager{ref_version = CurrentVer}, - GroupVer) when CurrentVer < GroupVer -> - raise(#'INV_OBJREF'{completion_status = ?COMPLETED_NO}). - - - -read_object_group(GroupID) -> - case mnesia:read({ft_replication_manager, GroupID}) of - [] -> - raise(#'OBJECT_NOT_EXIST'{completion_status = ?COMPLETED_NO}); - [ObjectGroup] -> - ObjectGroup - end. - - - -mk_FTRequestCtx(Expiration_time) -> - #'FT_FTRequestServiceContext'{ - client_id = atom_to_list(node()), - retention_id = orber_request_number:get(), - expiration_time = Expiration_time}. - - - -get_FTRequestCtx([#'FT_FTRequestServiceContext' - {client_id = Client_ID, retention_id = Retention_ID, - expiration_time = Expiration_time}|_Ctxs]) -> - {Client_ID, Retention_ID, Expiration_time}; -get_FTRequestCtx([]) -> - []; -get_FTRequestCtx([_Ctx|Ctxs]) -> - get_FTRequestCtx(Ctxs). - - - -get_FTGroupVersionCtx([#'FT_FTGroupVersionServiceContext' - {object_group_ref_version = Version}|_Ctxs]) -> - Version; -get_FTGroupVersionCtx([]) -> - []; -get_FTGroupVersionCtx([_Ctx|Ctxs]) -> - get_FTGroupVersionCtx(Ctxs). - |