%%-------------------------------------------------------------------- %% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1997-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 : orber_ifr_container.erl %% Purpose : Code for Container %%---------------------------------------------------------------------- -module(orber_ifr_container). -export(['_get_def_kind'/1, destroy/1, cleanup_for_destroy/1, %not in CORBA 2.0 lookup/2, contents/3, lookup_name/5, describe_contents/4, make_absolute_name/2, %not in CORBA 2.0 make_containing_repository/1, %not in CORBA 2.0 add_to_container/5, %not in CORBA 2.0 create_module/4, create_constant/6, create_struct/5, create_union/6, create_enum/5, create_alias/5, create_interface/5, create_exception/5 ]). -import(orber_ifr_utils,[get_field/2,select/2,construct/3,makeref/1,unique/0]). -import(lists,[map/2,filter/2,flatten/1,sublist/2]). -include_lib("orber/include/corba.hrl"). -include("orber_ifr.hrl"). -include("ifr_objects.hrl"). -include_lib("orber/include/ifr_types.hrl"). %%%====================================================================== %%% Container (IRObject) %%%---------------------------------------------------------------------- %%% Interfaces inherited from IRObject '_get_def_kind'(ObjRef) -> orber_ifr_irobject:'_get_def_kind'(ObjRef). %%% Note, that the destroy function is meant to be called within a %%% transaction called in the destroy function of an object which %%% inherits from Container. A Container should only be destroyed by %%% destroying the object that inherits from a Container. An attempt %%% to call this function in user code will result in unpredictable %%% results. %%% Don't type check the object reference. We need to be able to handle several %%% types of objects that inherit from Container. destroy(Container_objref) -> ObjList = cleanup_for_destroy(Container_objref), orber_ifr_irobject:destroy([Container_objref | ObjList]). cleanup_for_destroy(Container_objref) -> Contents = get_field(Container_objref, contents), map(fun destroy_thing/1, Contents) ++ Contents. %%% Destroy objects which inherit from Contained, i.e. objects that populate %%% the contents list of a Container. destroy_thing({ObjType,ObjID}) when ObjType == ir_ModuleDef -> orber_ifr_moduledef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_ConstantDef -> orber_ifr_constantdef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_TypedefDef -> orber_ifr_typedef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_StructDef -> orber_ifr_structdef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_UnionDef -> orber_ifr_uniondef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_EnumDef -> orber_ifr_enumdef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_AliasDef -> orber_ifr_aliasdef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_ExceptionDef -> orber_ifr_exceptiondef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_AttributeDef -> orber_ifr_attributedef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_OperationDef -> orber_ifr_operationdef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({ObjType,ObjID}) when ObjType == ir_InterfaceDef -> orber_ifr_interfacedef:cleanup_for_destroy({ObjType,ObjID}); destroy_thing({_ObjType,_ObjID}) -> %% Unknown object in Container contents. true. %%%---------------------------------------------------------------------- %%% Non-inherited interfaces lookup(ObjRef, Search_name) -> Contents = contents(ObjRef, dk_All, false), %% We now have the contents (a list of object references). %% Let's find all objects with the correct name. case filter(fun({Type,ID}) -> orber_ifr_contained:'_get_absolute_name'({Type,ID}) == Search_name end, Contents) of [Obj] -> Obj; X -> X end. contents(ObjRef, Limit_type, Exclude_inherited) -> Contents = flatten(get_field(ObjRef, contents) ++ inherited_contents(ObjRef,Exclude_inherited)), AllContents = Contents ++ flatten(subcontents(Limit_type,Contents)), limit_contents(Limit_type,AllContents). subcontents(_,[]) -> []; subcontents(Limit_type,Contents) -> map(fun(ObjRef) -> contents(ObjRef,Limit_type) end, Contents). contents({ir_Repository,ObjID},Limit_type) -> orber_ifr_repository:contents({ir_Repository,ObjID},Limit_type,false); contents({ir_ModuleDef,ObjID},Limit_type) -> orber_ifr_moduledef:contents({ir_ModuleDef,ObjID},Limit_type,false); contents({ir_InterfaceDef,ObjID},Limit_type) -> orber_ifr_interfacedef:contents({ir_InterfaceDef,ObjID},Limit_type,false); contents(_,_) -> []. limit_contents(dk_All,Contents) -> Contents; limit_contents(Limit_type,Contents) -> filter(fun(Obj_Ref) -> '_get_def_kind'(Obj_Ref) == Limit_type end, Contents). lookup_name(ObjRef, Search_name, Levels_to_search, Limit_type, Exclude_inherited) -> Contents = get_field(ObjRef, contents), AllContents = Contents ++ inherited_contents(ObjRef, Exclude_inherited), lookup_name(AllContents, Search_name, Levels_to_search, Limit_type). inherited_contents({ir_InterfaceDef,ObjID}, false) -> map(fun(ObjRef) -> get_field(ObjRef,contents) end, orber_ifr_interfacedef:'_get_base_interfaces'({ir_InterfaceDef,ObjID})); inherited_contents(_, false) -> []; inherited_contents(_, true) -> []. lookup_name(Contents, Search_name, Level, Limit_type) -> filter(fun(X) -> (orber_ifr_contained:'_get_id'(X) == Search_name) and ('_get_def_kind'(X) == Limit_type) end, Contents) ++ sublookup_name(Contents, Search_name, Level - 1, Limit_type). sublookup_name([],_,_,_) -> []; sublookup_name(_,_,0,_) -> []; sublookup_name(Contents, Search_name, Level, Limit_type) -> map(fun(X) -> Conts = subcontents(X), lookup_name(Conts, Search_name, Level - 1, Limit_type) end, Contents). subcontents({ir_Repository,ObjID}) -> get_field({ir_Repository,ObjID}, contents); subcontents({ir_ModuleDefObjType,ObjID}) -> get_field({ir_ModuleDef,ObjID}, contents); subcontents({ir_InterfaceDef,ObjID}) -> get_field({ir_InterfaceDef,ObjID}, contents); subcontents(_) -> []. describe_contents(ObjRef, Limit_type, Exclude_inherited, Max_returned_objs) -> Limited_contents = contents(ObjRef,Limit_type,Exclude_inherited), describe_contents(Limited_contents, Max_returned_objs, []). describe_contents(_, 0, Acc) -> Acc; describe_contents([], _Max_returned_objs, Acc) -> Acc; describe_contents([H|T], Max_returned_objs, Acc) -> Desc = orber_ifr_contained:describe(H), describe_contents(T, Max_returned_objs-1, [Desc|Acc]). %% This is a kludge. Se p. 6-11 in CORBA 2.0. make_absolute_name({ObjType,ObjID}, Name) -> case ObjType of ir_Repository -> "::" ++ Name; _ -> orber_ifr_contained:'_get_absolute_name'({ObjType,ObjID}) ++ "::" ++ Name end. %% This is a kludge. Se p. 6-15 in CORBA 2.0. make_containing_repository({ObjType,ObjID}) -> case ObjType of ir_Repository -> {ir_Repository,ObjID}; _ -> orber_ifr_contained:'_get_containing_repository'({ObjType, ObjID}) end. add_to_container(ContainerRef,Object, Id, Table, Index) -> F = fun() -> [Container_obj] = mnesia:wread(ContainerRef), case mnesia:index_read(Table, Id, Index) of [] -> ObjectRef = makeref(Object), New_container_obj = construct(Container_obj,contents, [ObjectRef | select(Container_obj,contents)]), mnesia:write(New_container_obj), mnesia:write(Object); _ -> mnesia:abort("duplicate") end end, case mnesia:transaction(F) of {aborted, "duplicate"} -> %% Must keep the misspelled word (must match IC generated code). exit({allready_registered, Id}); {aborted, Reason} -> orber:dbg("[~p] orber_ifr_container:add_to_container(~p). aborted:~n~p~n", [?LINE, Id, Reason], ?DEBUG_LEVEL), corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}); {atomic, _} -> ok end. add_to_light(#orber_light_ifr_ref{data = Data} = LRef, Id, Type, Name) -> BaseId = get_base_id(Data#lightdata.id, Id), NewScope = scoped_name(Data#lightdata.scope, Name, Type), F = fun() -> D = #orber_light_ifr{id = Id, module = list_to_atom(NewScope), type = Type, base_id = BaseId}, mnesia:write(D) end, case mnesia:transaction(F) of {aborted, Reason} -> orber:dbg("[~p] orber_ifr_container:add_to_light(~p). aborted:~n~p~n", [?LINE, Id, Reason], ?DEBUG_LEVEL), corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}); {atomic, _} -> LRef#orber_light_ifr_ref{data = Data#lightdata{scope = NewScope, id = BaseId}} end. get_base_id("", Id) -> Id; get_base_id(Id, _) -> Id. scoped_name("", Name, _) -> Name; scoped_name(Scope, _, ?IFR_ConstantDef) -> Scope; scoped_name(Scope, Name, _) -> Scope ++ "_" ++ Name. create_module(#orber_light_ifr_ref{} = LRef, Id, Name, _Version) -> add_to_light(LRef, Id, ?IFR_ModuleDef, Name); create_module(ObjRef, Id, Name, Version) -> New_module = #ir_ModuleDef{ir_Internal_ID = unique(), def_kind = dk_Module, contents = [], id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef, Name), containing_repository = make_containing_repository(ObjRef)}, add_to_container(ObjRef,New_module, Id, ir_ModuleDef, #ir_ModuleDef.id), makeref(New_module). create_constant(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Type, _Value) -> add_to_light(LRef, Id, ?IFR_ConstantDef, Name); create_constant(ObjRef, Id, Name, Version, Type, Value) -> IDL_typecode = get_field(Type,type), {Typecode, _} = Value, case IDL_typecode == Typecode of false -> orber:dbg("[~p] ~p:create_constant(~p, ~p, ~p, ~p, ~p, ~p);~n" "Wrong type.~n", [?LINE, ?MODULE, ObjRef, Id, Name, Version, Type, Value], ?DEBUG_LEVEL), corba:raise(#'INTF_REPOS'{completion_status=?COMPLETED_NO}); true -> New_constant = #ir_ConstantDef{ir_Internal_ID = unique(), def_kind = dk_Constant, id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef, Name), containing_repository = make_containing_repository(ObjRef), type = get_field(Type,type), type_def = Type, value = Value}, add_to_container(ObjRef,New_constant, Id, ir_ConstantDef, #ir_ConstantDef.id), makeref(New_constant) end. create_struct(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Members) -> add_to_light(LRef, Id, ?IFR_StructDef, Name); create_struct(ObjRef, Id, Name, Version, Members) -> New_struct = #ir_StructDef{ir_Internal_ID = unique(), def_kind = dk_Struct, id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef, Name), containing_repository = make_containing_repository(ObjRef), type = {tk_struct, Id, Name, map(fun(#structmember{name=MemName, type=Type}) -> {MemName,Type} end, Members)}, members = Members}, add_to_container(ObjRef, New_struct, Id, ir_StructDef, #ir_StructDef.id), makeref(New_struct). create_union(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Discriminator_type, _Members) -> add_to_light(LRef, Id, ?IFR_UnionDef, Name); create_union(ObjRef, Id, Name, Version, Discriminator_type, Members) -> Discriminator_type_code = get_field(Discriminator_type, type), New_union = #ir_UnionDef{ir_Internal_ID = unique(), def_kind = dk_Union, id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef, Name), containing_repository = make_containing_repository(ObjRef), type = {tk_union, Id, Name, Discriminator_type_code, -1, map(fun(#unionmember{name=MemName, label=Label, type=Type}) -> {Label,MemName,Type} end, Members)}, discriminator_type = Discriminator_type_code, discriminator_type_def = Discriminator_type, members = Members}, add_to_container(ObjRef, New_union, Id, ir_UnionDef, #ir_UnionDef.id), makeref(New_union). create_enum(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Members) -> add_to_light(LRef, Id, ?IFR_EnumDef, Name); create_enum(ObjRef, Id, Name, Version, Members) -> New_enum = #ir_EnumDef{ir_Internal_ID = unique(), def_kind = dk_Enum, id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef, Name), containing_repository = make_containing_repository(ObjRef), type = {tk_enum, Id, Name, Members}, members = Members}, add_to_container(ObjRef, New_enum, Id, ir_EnumDef, #ir_EnumDef.id), makeref(New_enum). create_alias(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Original_type) -> add_to_light(LRef, Id, ?IFR_AliasDef, Name); create_alias(ObjRef, Id, Name, Version, Original_type) -> New_alias = #ir_AliasDef{ir_Internal_ID = unique(), def_kind = dk_Alias, id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef, Name), containing_repository = make_containing_repository(ObjRef), type = {tk_alias, Id, Name, get_field(Original_type,type)}, original_type_def = Original_type}, add_to_container(ObjRef, New_alias, Id, ir_AliasDef, #ir_AliasDef.id), makeref(New_alias). create_interface(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Base_interfaces) -> add_to_light(LRef, Id, ?IFR_InterfaceDef, Name); create_interface(ObjRef, Id, Name, Version, Base_interfaces) -> New_interface = #ir_InterfaceDef{ir_Internal_ID = unique(), def_kind = dk_Interface, contents = [], id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef,Name), containing_repository = make_containing_repository(ObjRef), type = {tk_objref, Id, Name}, base_interfaces = Base_interfaces}, add_to_container(ObjRef, New_interface, Id, ir_InterfaceDef, #ir_InterfaceDef.id), makeref(New_interface). create_exception(#orber_light_ifr_ref{} = LRef, Id, Name, _Version, _Members) -> add_to_light(LRef, Id, ?IFR_ExceptionDef, Name); create_exception(ObjRef, Id, Name, Version, Members) -> New_exception = #ir_ExceptionDef{ir_Internal_ID = unique(), def_kind = dk_Exception, id = Id, name = Name, version = Version, defined_in = ObjRef, absolute_name = make_absolute_name(ObjRef,Name), containing_repository = make_containing_repository(ObjRef), type = {tk_except, Id, Name, map(fun(#structmember{name=MemName, type=Type}) -> {MemName,Type} end, Members)}, members = Members}, add_to_container(ObjRef, New_exception, Id, ir_ExceptionDef, #ir_ExceptionDef.id), makeref(New_exception).