diff options
Diffstat (limited to 'lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl')
-rw-r--r-- | lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl | 1415 |
1 files changed, 1415 insertions, 0 deletions
diff --git a/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl new file mode 100644 index 0000000000..0b73100540 --- /dev/null +++ b/lib/cosEventDomain/src/CosEventDomainAdmin_EventDomain_impl.erl @@ -0,0 +1,1415 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% File : CosEventDomainAdmin_EventDomain_impl.erl +%% Description : +%% +%%---------------------------------------------------------------------- +-module('CosEventDomainAdmin_EventDomain_impl'). + +%%---------------------------------------------------------------------- +%% Include files +%%---------------------------------------------------------------------- +-include_lib("orber/include/corba.hrl"). +-include_lib("orber/include/ifr_types.hrl"). +-include_lib("cosNotification/include/CosNotifyChannelAdmin.hrl"). +-include_lib("cosNotification/include/CosNotification.hrl"). + +-include("cosEventDomainApp.hrl"). +-include("CosEventDomainAdmin.hrl"). + +%%---------------------------------------------------------------------- +%% External exports +%%---------------------------------------------------------------------- +-export([init/1, + terminate/2, + code_change/3, + handle_info/2]). + +%%------------------ CosEventDomainAdmin::EventDomain ------------------ +-export([add_channel/3, + get_all_channels/2, + get_channel/3, + remove_channel/3, + add_connection/3, + get_all_connections/2, + get_connection/3, + remove_connection/3, + get_offer_channels/3, + get_subscription_channels/3, + destroy/2, + get_cycles/2, + get_diamonds/2, + set_default_consumer_channel/3, + set_default_supplier_channel/3, + connect_push_consumer/3, + connect_pull_consumer/3, + connect_push_supplier/3, + connect_pull_supplier/3, + connect_structured_push_consumer/3, + connect_structured_pull_consumer/3, + connect_structured_push_supplier/3, + connect_structured_pull_supplier/3, + connect_sequence_push_consumer/3, + connect_sequence_pull_consumer/3, + connect_sequence_push_supplier/3, + connect_sequence_pull_supplier/3, + connect_push_consumer_with_id/4, + connect_pull_consumer_with_id/4, + connect_push_supplier_with_id/4, + connect_pull_supplier_with_id/4, + connect_structured_push_consumer_with_id/4, + connect_structured_pull_consumer_with_id/4, + connect_structured_push_supplier_with_id/4, + connect_structured_pull_supplier_with_id/4, + connect_sequence_push_consumer_with_id/4, + connect_sequence_pull_consumer_with_id/4, + connect_sequence_push_supplier_with_id/4, + connect_sequence_pull_supplier_with_id/4]). + +%%------------------ CosNotification::QoSAdmin ------------------------- +-export([get_qos/2, + set_qos/3, + validate_qos/3]). + +%%------------------ CosNotification::AdminPropertiesAdmin ------------- +-export([get_admin/2, + set_admin/3]). + + + +%%---------------------------------------------------------------------- +%% Internal exports +%%---------------------------------------------------------------------- +-export([]). + +%%---------------------------------------------------------------------- +%% Records +%%---------------------------------------------------------------------- +-record(state, {parent_pid, id, graph, ch_counter=-1, + co_counter=-1, def_supplier, def_consumer, diamonds, cyclic}). + +-record(connection, {supplier, consumer, data}). + +%%---------------------------------------------------------------------- +%% Macros +%%---------------------------------------------------------------------- + +%%====================================================================== +%% External functions +%%====================================================================== +%%---------------------------------------------------------------------- +%% Function : init/1 +%% Returns : {ok, State} | +%% {ok, State, Timeout} | +%% ignore | +%% {stop, Reason} +%% Description: Initiates the server +%%---------------------------------------------------------------------- +init([ParentPid, MyId, QoS, _Admin]) -> + process_flag(trap_exit, true), + Diamonds = case lists:keysearch(?DiamondDetection, 1, QoS) of + false -> + ?ForbidDiamonds; + {value, {_, Value}} -> + Value + end, + case lists:keysearch(?CycleDetection, 1, QoS) of + {value, {_, ?AuthorizeCycles}} -> + {ok, #state{parent_pid = ParentPid, id = MyId, + graph = digraph:new([private]), + diamonds = Diamonds, cyclic = ?AuthorizeCycles}}; + _ -> + {ok, #state{parent_pid = ParentPid, id = MyId, + graph = digraph:new([acyclic, private]), + diamonds = Diamonds, cyclic = ?ForbidCycles}} + end. + +%%---------------------------------------------------------------------- +%% Function : terminate/2 +%% Returns : any (ignored by gen_server) +%% Description: Shutdown the server +%%---------------------------------------------------------------------- +terminate(_Reason, #state{graph = DG} = _State) -> + Connections = digraph:edges(DG), + close_connections(DG, Connections), + digraph:delete(DG), + ok. + +%%---------------------------------------------------------------------- +%% Function : code_change/3 +%% Returns : {ok, NewState} +%% Description: Convert process state when code is changed +%%---------------------------------------------------------------------- +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------- +%% Function : handle_info/2 +%% Returns : {noreply, State} | +%% {stop, Reason, State} +%% Description: Handle, for example, exit signals. +%%---------------------------------------------------------------------- +handle_info({'EXIT', Pid, Reason}, #state{parent_pid = Pid} = State) -> + {stop, Reason, State}; +handle_info(_Info, State) -> + {noreply, State}. + +%%---------------------------------------------------------------------- +%%------------------ CosEventDomainAdmin::EventDomain ------------------ +%%---------------------------------------------------------------------% +%% Function : add_channel +%% Arguments : Channel - CosNotifyChannelAdmin::EventChannel +%% Returns : MemberId - long() +%% Description: +%%---------------------------------------------------------------------- +add_channel(_OE_This, #state{ch_counter=C, graph = DG} = State, Channel) -> + type_check(Channel, 'CosNotifyChannelAdmin_EventChannel'), + Id = cosEventDomainApp:create_id(C), + digraph:add_vertex(DG, Id, Channel), + {reply, Id, State#state{ch_counter=Id}}. + +%%---------------------------------------------------------------------% +%% Function : get_all_channels +%% Arguments : - +%% Returns : CosEventDomainAdmin::MemberIDSeq ([long()]) +%% Description: +%%---------------------------------------------------------------------- +get_all_channels(_OE_This, #state{graph = DG} = State) -> + {reply, digraph:vertices(DG), State}. + +%%---------------------------------------------------------------------% +%% Function : get_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::EventChannel | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} +%% Description: +%%---------------------------------------------------------------------- +get_channel(_OE_This, #state{graph = DG} = State, Id) -> + {reply, lookup_channel(DG, Id), State}. + +%%---------------------------------------------------------------------% +%% Function : remove_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} +%% Description: +%%---------------------------------------------------------------------- +remove_channel(_OE_This, #state{graph = DG} = State, Id) -> + lookup_channel(DG, Id), + close_connections(DG, digraph:edges(DG, Id)), + digraph:del_vertex(DG, Id), + {reply, ok, State}. + +%%---------------------------------------------------------------------% +%% Function : add_connection +%% Arguments : Connection - CosEventDomainAdmin::Connection +%% Returns : ConnectionID | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_TypeError'{}} | +%% {'EXCEPTION', #'CosEventDomainAdmin_AlreadyExists'{}} | +%% {'EXCEPTION', #'CosEventDomainAdmin_CycleCreationForbidden'{cyc}} | +%% {'EXCEPTION', #'CosEventDomainAdmin_DiamondCreationForbidden'{diam}} +%% Description: +%%---------------------------------------------------------------------- +add_connection(_OE_This, #state{graph = DG, co_counter = C} = State, + Connection) when is_record(Connection, + 'CosEventDomainAdmin_Connection') -> + SId = Connection#'CosEventDomainAdmin_Connection'.supplier_id, + SChannel = lookup_channel(DG, SId), + CId = Connection#'CosEventDomainAdmin_Connection'.consumer_id, + CChannel = lookup_channel(DG, CId), + case lists:member(CId, digraph:out_neighbours(DG, SId)) of + false -> + Id = cosEventDomainApp:create_id(C), + %% Try to insert the new connection before we actually setup a connection. + %% Note that #connection is NOT complete, hence, we must update it later. + case digraph:add_edge(DG, Id, SId, CId, #connection{data=Connection}) of + {error, {bad_edge, Path}} -> + corba:raise(#'CosEventDomainAdmin_CycleCreationForbidden'{cyc=Path}); + Id when State#state.diamonds == ?AuthorizeDiamonds -> + case catch setup_connection(Connection, SChannel, CChannel) of + {ok, SProxy, CProxy} -> + %% Now we can update the connection with complete data. + digraph:add_edge(DG, Id, SId, CId, #connection{supplier=SProxy, + consumer=CProxy, + data=Connection}), + {reply, Id, State#state{co_counter = Id}}; + {'EXCEPTION', E} -> + digraph:del_edge(DG, Id), + corba:raise(E); + What -> + digraph:del_edge(DG, Id), + orber:dbg("[~p] CosEventDomainAdmin_EventDomain:" + "add_connection(~p);~nFailed setting up" + " connection due to: ~p", + [?LINE, Connection, What], ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_MAYBE}) + end; + Id -> + case get_diamonds_helper(State, false, SId) of + [] -> + case catch setup_connection(Connection, SChannel, CChannel) of + {ok, SProxy, CProxy} -> + %% Now we can update the connection with complete data. + digraph:add_edge(DG, Id, SId, CId, #connection{supplier=SProxy, + consumer=CProxy, + data=Connection}), + {reply, Id, State#state{co_counter = Id}}; + {'EXCEPTION', E} -> + digraph:del_edge(DG, Id), + corba:raise(E); + What -> + digraph:del_edge(DG, Id), + orber:dbg("[~p] CosEventDomainAdmin_EventDomain:" + "add_connection(~p);~nFailed setting" + " up connection due to: ~p", + [?LINE, Connection, What], + ?DEBUG_LEVEL), + corba:raise(#'INTERNAL'{completion_status=?COMPLETED_MAYBE}) + end; + Diamond -> + %% Since no diamonds should exist the returned list can + %% only describe the diamond we just created. + digraph:del_edge(DG, Id), + corba:raise(#'CosEventDomainAdmin_DiamondCreationForbidden' + {diam=Diamond}) + end + end; + true -> + corba:raise(#'CosEventDomainAdmin_AlreadyExists'{}) + end. + + +%%---------------------------------------------------------------------% +%% Function : get_all_connections +%% Arguments : - +%% Returns : CosEventDomainAdmin::ConnectionIDSeq - [long()] +%% Description: +%%---------------------------------------------------------------------- +get_all_connections(_OE_This, #state{graph = DG} = State) -> + {reply, digraph:edges(DG), State}. + +%%---------------------------------------------------------------------% +%% Function : get_connection +%% Arguments : Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : CosEventDomainAdmin::Connection | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_connection(_OE_This, #state{graph = DG} = State, Id) -> + {reply, lookup_connection_data(DG, Id), State}. + +%%---------------------------------------------------------------------% +%% Function : remove_connection +%% Arguments : Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +remove_connection(_OE_This, #state{graph = DG} = State, Id) -> + #connection{supplier=S, consumer=C, data=Connection} = + lookup_connection(DG, Id), + close_connection(Connection, S, C), + digraph:del_edge(DG, Id), + {reply, ok, State}. + + +%%---------------------------------------------------------------------% +%% Function : get_offer_channels +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ChannelIDSeq | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_offer_channels(_OE_This, #state{graph = DG, cyclic = Cyclic} = State, Id) -> + lookup_channel(DG, Id), + case digraph:vertex(DG, Id) of + {Id, _Channel} when Cyclic == ?ForbidCycles -> + {reply, digraph_utils:reaching_neighbours([Id], DG), State}; + {Id, _Channel} -> + %% If cyclic graphs is allowed 'Id' will appear in the returned list. + %% Hence, we must delete it. + {reply,lists:delete(Id, digraph_utils:reaching_neighbours([Id], DG)), + State}; + false -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% Function : get_subscription_channels +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ChannelIDSeq | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +get_subscription_channels(_OE_This, #state{graph = DG, cyclic = Cyclic} = State, Id) -> + lookup_channel(DG, Id), + case digraph:vertex(DG, Id) of + {Id, _Channel} when Cyclic == ?ForbidCycles -> + {reply, digraph_utils:reachable_neighbours([Id], DG), State}; + {Id, _Channel} -> + %% If cyclic graphs is allowed 'Id' will appear in the returned list. + %% Hence, we must delete it. + {reply, lists:delete(Id, digraph_utils:reachable_neighbours([Id], DG)), + State}; + false -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% Function : destroy +%% Arguments : - +%% Returns : ok +%% Description: +%%---------------------------------------------------------------------- +destroy(_OE_This, #state{graph = _DG} = State) -> + {stop, normal, ok, State}. + +%%---------------------------------------------------------------------% +%% Function : get_cycles +%% Arguments : - +%% Returns : CosEventDomainAdmin::CycleSeq +%% Description: +%%---------------------------------------------------------------------- +get_cycles(_OE_This, #state{cyclic = ?ForbidCycles} = State) -> + {reply, [], State}; +get_cycles(_OE_This, #state{graph = DG} = State) -> + {reply, digraph_utils:cyclic_strong_components(DG), State}. + +%%---------------------------------------------------------------------- +%% Function : get_diamonds +%% Arguments : - +%% Returns : CosEventDomainAdmin::DiamondSeq +%% Description: +%%---------------------------------------------------------------------- +get_diamonds(_OE_This, #state{diamonds = ?ForbidDiamonds} = State) -> + {reply, [], State}; +get_diamonds(_OE_This, State) -> + {reply, get_diamonds_helper(State, true), State}. + +get_diamonds_helper(#state{graph = DG} = _State, FindAll) -> + case find_candidates(DG) of + {[], _, _} -> + []; + {_, [], _} -> + []; + {COut, CIn, Max} -> + %% In this case we cannot tell if a diamond exists. Got to + %% check the paths between the candidates. + evaluate_candidates(DG, COut, CIn, [], Max, FindAll) + end. + +get_diamonds_helper(#state{graph = DG} = _State, FindAll, Vertex) -> + case find_candidates(DG, Vertex) of + {[], _, _} -> + []; + {_, [], _} -> + []; + {COut, CIn, Max} -> + %% In this case we cannot tell if a diamond exists. Got to + %% check the paths between the candidates. + evaluate_candidates(DG, COut, CIn, [], Max, FindAll) + end. + +%%---------------------------------------------------------------------% +%% Function : set_default_consumer_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +set_default_consumer_channel(_OE_This, #state{graph = DG} = State, Id) -> + lookup_channel(DG, Id), + {reply, ok, State#state{def_consumer=Id}}. + +%%---------------------------------------------------------------------% +%% Function : set_default_supplier_channel +%% Arguments : Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : ok | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +set_default_supplier_channel(_OE_This, #state{graph = DG} = State, Id) -> + lookup_channel(DG, Id), + {reply, ok, State#state{def_supplier=Id}}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_consumer +%% Arguments : PC - CosEventComm::PushConsumer +%% Returns : CosNotifyChannelAdmin::ProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + type_check(PC, 'CosEventComm_PushConsumer'), + Proxy = connect_a_push_consumer(Ch, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_consumer +%% Arguments : PC - CosEventComm::PullConsumer +%% Returns : CosNotifyChannelAdmin::ProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_consumer(_OE_This, #state{def_consumer = Ch} = State, PC) -> + Proxy = connect_a_pull_consumer(Ch, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_supplier +%% Arguments : PS - CosEventComm::PushSupplier +%% Returns : CosNotifyChannelAdmin::ProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_supplier(_OE_This, #state{def_supplier = Ch} = State, PS) -> + Proxy = connect_a_push_supplier(Ch, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_supplier +%% Arguments : PS - CosEventComm::PullSupplier +%% Returns : CosNotifyChannelAdmin::ProxyPullConsumer +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + type_check(PS, 'CosEventComm_PullSupplier'), + Proxy = connect_a_pull_supplier(Ch, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_consumer +%% Arguments : PC - CosNotifyComm::StructuredPushConsumer +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + type_check(PC, 'CosNotifyComm_StructuredPushConsumer'), + Proxy = connect_a_push_consumer(Ch, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_consumer +%% Arguments : PC - CosNotifyComm::StructuredPullConsumer +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + Proxy = connect_a_pull_consumer(Ch, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_supplier +%% Arguments : PS - CosNotifyComm::StructuredPushSupplier +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + Proxy = connect_a_push_supplier(Ch, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_supplier +%% Arguments : PS - CosNotifyComm::StructuredPullSupplier +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + type_check(PS, 'CosNotifyComm_StructuredPullSupplier'), + Proxy = connect_a_pull_supplier(Ch, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_consumer +%% Arguments : PC - CosNotifyComm::SequencePushConsumer +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + type_check(PC, 'CosNotifyComm_SequencePushConsumer'), + Proxy = connect_a_push_consumer(Ch, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_consumer +%% Arguments : PC - CosNotifyComm::SequencePullConsumer +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_consumer(_OE_This, #state{def_supplier = Ch} = State, PC) -> + Proxy = connect_a_pull_consumer(Ch, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_supplier +%% Arguments : PS - CosNotifyComm::SequencePushSupplier +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + Proxy = connect_a_push_supplier(Ch, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_supplier +%% Arguments : PS - CosNotifyComm::SequencePullSupplier +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_supplier(_OE_This, #state{def_consumer = Ch} = State, PS) -> + type_check(PS, 'CosNotifyComm_SequencePullSupplier'), + Proxy = connect_a_pull_supplier(Ch, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_consumer_with_id +%% Arguments : PC - CosEventComm::PushConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + type_check(PC, 'CosEventComm_PushConsumer'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_consumer(Channel, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_consumer_with_id +%% Arguments : PC - CosEventComm::PullConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_consumer(Channel, PC, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_push_supplier_with_id +%% Arguments : PS - CosEventComm::PushSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_supplier(Channel, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_pull_supplier_with_id +%% Arguments : PS - CosEventComm::PullSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::ProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + type_check(PS, 'CosEventComm_PullSupplier'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_supplier(Channel, PS, 'ANY_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_consumer_with_id +%% Arguments : PC - CosNotifyComm::StructuredPushConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + type_check(PC, 'CosNotifyComm_StructuredPushConsumer'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_consumer(Channel, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_consumer_with_id +%% Arguments : PC - CosNotifyComm::StructuredPullConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_consumer(Channel, PC, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_push_supplier_with_id +%% Arguments : PS - CosNotifyComm::StructuredPushSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_supplier(Channel, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_structured_pull_supplier_with_id +%% Arguments : PS - CosNotifyComm::StructuredPullSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::StructuredProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_structured_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + type_check(PS, 'CosNotifyComm_StructuredPullSupplier'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_supplier(Channel, PS, 'STRUCTURED_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_consumer_with_id +%% Arguments : PC - CosNotifyComm::SequencePushConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + type_check(PC, 'CosNotifyComm_SequencePushConsumer'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_consumer(Channel, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_consumer_with_id +%% Arguments : PC - CosNotifyComm::SequencePullConsumer +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullSupplier | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_consumer_with_id(_OE_This, #state{graph = DG} = State, PC, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_consumer(Channel, PC, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_push_supplier_with_id +%% Arguments : PS - CosNotifyComm::SequencePushSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPushConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_push_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + Channel = lookup_channel(DG, Id), + Proxy = connect_a_push_supplier(Channel, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + +%%---------------------------------------------------------------------% +%% Function : connect_sequence_pull_supplier_with_id +%% Arguments : PS - CosNotifyComm::SequencePullSupplier +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::SequenceProxyPullConsumer | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} | +%% Description: +%%---------------------------------------------------------------------- +connect_sequence_pull_supplier_with_id(_OE_This, #state{graph = DG} = State, PS, Id) -> + type_check(PS, 'CosNotifyComm_SequencePullSupplier'), + Channel = lookup_channel(DG, Id), + Proxy = connect_a_pull_supplier(Channel, PS, 'SEQUENCE_EVENT'), + {reply, Proxy, State}. + + +%%---------------------------------------------------------------------- +%%------------------ CosNotification::QoSAdmin ------------------------- +%%---------------------------------------------------------------------% +%% Function : get_qos +%% Arguments : - +%% Returns : CosNotification::QoSProperties +%% Description: +%%---------------------------------------------------------------------- +get_qos(_OE_This, #state{cyclic = Cyclic, diamonds = Diamonds} = State) -> + {reply, [#'CosNotification_Property' + {name = ?DiamondDetection, + value = any:create(orber_tc:short(), Diamonds)}, + #'CosNotification_Property' + {name = ?CycleDetection, + value = any:create(orber_tc:short(), Cyclic)}], State}. + +%%---------------------------------------------------------------------% +%% Function : set_qos +%% Arguments : NewQoS - CosNotification::QoSProperties +%% Returns : ok | +%% {'EXCEPTION', #'CosNotification_UnsupportedQoS{}} +%% Description: +%%---------------------------------------------------------------------- +set_qos(_OE_This, State, NewQoS) -> + QoS = cosEventDomainApp:get_qos(NewQoS), + set_qos_helper(QoS, State, []). + +set_qos_helper([], State, []) -> + {reply, ok, State}; +set_qos_helper([], _, Errors) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}); +set_qos_helper([{?DiamondDetection, Diamonds}|T], #state{diamonds = Diamonds} = State, + Errors) -> + set_qos_helper(T, State, Errors); +set_qos_helper([{?CycleDetection, Cyclic}|T], #state{cyclic = Cyclic} = State, + Errors) -> + set_qos_helper(T, State, Errors); +set_qos_helper([{?DiamondDetection, ?AuthorizeDiamonds}|T], State, Errors) -> + %% Diamonds have not been allowed so far so it's safe to allow it. + set_qos_helper(T, State#state{diamonds = ?AuthorizeDiamonds}, Errors); +set_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Errors) -> + %% If any diamonds already exists we cannot allow this. Hence, now we must check + %% if we can update the QoS. + case get_diamonds_helper(State, false) of + [] -> + set_qos_helper(T, State#state{diamonds = ?ForbidDiamonds}, Errors); + _ -> + set_qos_helper(T, State, + [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?DiamondDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?AuthorizeDiamonds)}}|Errors]) + end; +set_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State, Errors) -> + %% Currently we do not support changing the Cycle schema. If we want to, + %% we must copy the graph to a new instance of the correct type. + set_qos_helper(T, State, + [#'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?CycleDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), Cyclic), + high_val=any:create(orber_tc:short(), Cyclic)}}|Errors]). + +%%---------------------------------------------------------------------% +%% Function : validate_qos +%% Arguments : WantedQoS - CosNotification::QoSProperties +%% Returns : {ok, CosNotification::NamedPropertyRangeSeq} | +%% {'EXCEPTION', #'CosNotification_UnsupportedQoS{}} +%% Description: NamedPropertyRangeSeq is of out-type +%%---------------------------------------------------------------------- +validate_qos(_OE_This, State, WantedQoS) -> + QoS = cosEventDomainApp:get_qos(WantedQoS), + {reply, {ok, validate_qos_helper(QoS, State, [], [])}, State}. + +validate_qos_helper([], _, Properties, []) -> + Properties; +validate_qos_helper([], _, _, Errors) -> + corba:raise(#'CosNotification_UnsupportedQoS'{qos_err = Errors}); +validate_qos_helper([{?DiamondDetection, ?ForbidDiamonds}|T], State, Properties, + Errors) -> + case get_diamonds_helper(State, false) of + [] -> + Property = + #'CosNotification_NamedPropertyRange' + {name = ?DiamondDetection, + range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?ForbidDiamonds)}}, + validate_qos_helper(T, State, [Property|Properties], Errors); + _ -> + Error = + #'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?DiamondDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?AuthorizeDiamonds)}}, + validate_qos_helper(T, State, Properties, [Error|Errors]) + end; +validate_qos_helper([{?DiamondDetection, ?AuthorizeDiamonds}|T], State, Properties, + Errors) -> + Property = + #'CosNotification_NamedPropertyRange' + {name = ?DiamondDetection, + range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), ?AuthorizeDiamonds), + high_val=any:create(orber_tc:short(), ?ForbidDiamonds)}}, + validate_qos_helper(T, State, [Property|Properties], Errors); +validate_qos_helper([{?CycleDetection, Cyclic}|T], #state{cyclic = Cyclic} = State, + Properties, Errors) -> + validate_qos_helper(T, State, Properties, Errors); +validate_qos_helper([{?CycleDetection, _}|T], #state{cyclic = Cyclic} = State, + Properties, Errors) -> + Error = + #'CosNotification_PropertyError' + {code = 'UNAVAILABLE_VALUE', + name = ?CycleDetection, + available_range = #'CosNotification_PropertyRange' + {low_val=any:create(orber_tc:short(), Cyclic), + high_val=any:create(orber_tc:short(), Cyclic)}}, + validate_qos_helper(T, State, Properties, [Error|Errors]). + + +%%---------------------------------------------------------------------- +%%------------------ CosNotification::AdminPropertiesAdmin ------------- +%%---------------------------------------------------------------------% +%% Function : get_admin +%% Arguments : - +%% Returns : CosNotification::AdminProperties +%% Description: No Admins currently supported +%%---------------------------------------------------------------------- +get_admin(_OE_This, State) -> + {reply, [], State}. + +%%---------------------------------------------------------------------% +%% Function : set_admin +%% Arguments : NewAdmins - CosNotification::AdminProperties +%% Returns : ok | +%% {'EXCEPTION', #'CosNotification_UnsupportedAdmin{}} +%% Description: No Admins currently supported +%%---------------------------------------------------------------------- +set_admin(_OE_This, State, NewAdmins) -> + cosEventDomainApp:get_admin(NewAdmins), + {reply, ok, State}. + + +%%====================================================================== +%% Internal functions +%%====================================================================== +%%---------------------------------------------------------------------% +%% Function : find_candidates +%% Arguments : Digraph reference +%% (Vertex - if we're interested in a specific vertex. +%% Returns : {[SourceVertices], [SinkVertices], Max} +%% SourceVertices - {Vertice, [ReachableVertices]} +%% SinkVertices - {Vertice, [ReachingVertices]} +%% Max - number of edges in the graph. +%% Description: To be a part of a diamond ("transitive" relation xRy, yRz => xRz; +%% in comparison with discrete mathematics we do not require that the +%% entire graph is transitive) a vertex must have more than one +%% outgoing and/or incoming. Hence, a digraph must contain at least +%% one vertex with more than one outgoing edges and at least +%% one with more than one incoming edges for a diamond to exist. +%% Hence, the purpose of this function is to find vertices that +%% look like: +%% +%% Vout->V1 V6->Vin +%% \ and ^ +%% +->V2 | +%% V8--+ +%%---------------------------------------------------------------------- +find_candidates(DG) -> + Edges = digraph:edges(DG), + {COut, CIn, Max} = find_candidates_helper(Edges, [], [], DG, 0), + {filter_candidates(COut), filter_candidates(CIn), Max}. + + +find_candidates(DG, _Vertex) -> + %% We should use the fact that we know one of the vertices. + Edges = digraph:edges(DG), + {COut, CIn, Max} = find_candidates_helper(Edges, [], [], DG, 0), + {filter_candidates(COut), filter_candidates(CIn), Max}. + +find_candidates_helper([], AccOut, AccIn, _, Counter) -> + {lists:sort(AccOut), lists:sort(AccIn), Counter}; +find_candidates_helper([H|T], AccOut, AccIn, DG, Counter) -> + {H, V1, V2, _Label} = digraph:edge(DG, H), + find_candidates_helper(T, [{V1, V2}|AccOut], [{V2,V1}|AccIn], DG, Counter+1). + +filter_candidates([]) -> + []; +filter_candidates([{V1, V2}|T]) -> + filter_candidates([{V1, V2}|T], V1, [], []). +filter_candidates([], _V, [_Acc1], Acc2) -> + %% Only one in/out connection. Hence, cannot be start- or end-point + %% of a diamond. + lists:reverse(Acc2); +filter_candidates([], V, Acc1, Acc2) -> + lists:reverse([{V, lists:reverse(Acc1)}|Acc2]); +filter_candidates([{V1, V2}|T], V1, Acc1, Acc2) -> + filter_candidates(T, V1, [V2|Acc1], Acc2); +filter_candidates([{V1, V2}|T], _V, [_Acc1], Acc2) -> + %% Only one in/out connection. Hence, cannot be start- or end-point + %% of a diamond. + filter_candidates(T, V1, [V2], Acc2); +filter_candidates([{V1, V2}|T], V, Acc1, Acc2) -> + filter_candidates(T, V1, [V2], [{V, lists:reverse(Acc1)}|Acc2]). + +%%---------------------------------------------------------------------% +%% Function : evaluate_candidates +%% Arguments : - +%% Returns : [Diamond] +%% Description: There are several scenarios but they can be categorized as: +%% (1) (2) (3) (4) +%% 2 2 2-..-56 +%% / \ / \ / \ +%% 1---4 1---4 1---4 1 4 +%% \ / \ / \ / +%% 3 3 3-..-11 +%% +%% The purpose of this function is to find these in the cheapest +%% way possible. For complex diamonds (may also include cycles) +%% duplicates may be generated. For example, #2/#3 is a sub-set of #1 +%% but they are as well diamonds. +%%---------------------------------------------------------------------- +evaluate_candidates(_DG, [], _, Acc, _Max, _) -> + Acc; +evaluate_candidates(DG, [{V, OutV}|T], CIn, Acc, Max, FindAll) -> + case evaluate_candidates_helper(DG, V, OutV, CIn, [], FindAll) of + [] -> + evaluate_candidates(DG, T, CIn, Acc, Max, FindAll); + Diamonds when FindAll == true -> + %% May be more than one diamond. + evaluate_candidates(DG, T, CIn, Diamonds ++ Acc, Max, FindAll); + Diamond -> + Diamond + end. + +evaluate_candidates_helper(_, _, _, _, [Diamond], false) -> + Diamond; +evaluate_candidates_helper(_, _, _, [], Diamonds, _) -> + Diamonds; +evaluate_candidates_helper(DG, V1, OutV, [{V1, _InV}|T], Diamonds, FindAll) -> + evaluate_candidates_helper(DG, V1, OutV, T, Diamonds, FindAll); +evaluate_candidates_helper(DG, V1, OutV, [{V2, InV}|T], Diamonds, FindAll) -> + case double_match(OutV, InV, [], V1, V2) of + [] -> + case is_member(InV, V1) of + true -> + %% At this point we know that we have: + %% x -> y + %% For this pair to be a part of a diamond we have two options: + %% (1) x - y (2) x ---- y + %% \ / or \ / or a additional path besides z1-zN, + %% z z1-zN + case double_match_exclude(OutV, InV, [], V1, V2) of + [] -> + %% Nope it's not #1. + case digraph_match(OutV, V2, V1, DG, 1) of + false -> + evaluate_candidates_helper(DG, V1, OutV, T, + Diamonds, FindAll); + Diamond -> + evaluate_candidates_helper(DG, V1, OutV, T, + [[[V1, V2]|Diamond]|Diamonds], + FindAll) + end; + Diamond -> + %% We've found a diamond looking like: + %% x - y xRy, yRz => xRz + %% \ / + %% z + evaluate_candidates_helper(DG, V1, OutV, T, + [[[V1, V2]|Diamond]|Diamonds], + FindAll) + end; + false -> + case digraph_match(OutV, V2, V1, DG) of + false -> + evaluate_candidates_helper(DG, V1, OutV, T, + Diamonds, FindAll); + Diamond -> + evaluate_candidates_helper(DG, V1, OutV, T, + [Diamond|Diamonds], FindAll) + end + end; + Diamond -> + %% We've found a diamond looking something like: + %% 2 + %% / \ + %% 1-5-4 V1 eq. 1, V2 eq 4. + %% \ / + %% 3 + evaluate_candidates_helper(DG, V1, OutV, T, [Diamond|Diamonds], + FindAll) + end. + +is_member([], _) -> + false; +is_member([H|_], H) -> + true; +is_member([H|_], H2) when H > H2 -> + %% Since it's a sorted list no need to look any further. + false; +is_member([_|T], H) -> + is_member(T, H). + +double_match([], _, [_Matched], _, _) -> + []; +double_match([], _, Matched, _, _) -> + Matched; +double_match(_, [], [_Matched], _, _) -> + []; +double_match(_, [], Matched, _, _) -> + Matched; +double_match([H|T1], [H|T2], Matched, V1, V2) -> + double_match(T1, T2, [[V1,H,V2] | Matched], V1, V2); +double_match([H1|T1], [H2|T2], Matched, V1, V2) when H1 > H2 -> + double_match([H1|T1], T2, Matched, V1, V2); +double_match([_H1|T1], [H2|T2], Matched, V1, V2) -> + double_match(T1, [H2|T2], Matched, V1, V2). + +double_match_exclude([], _, Matched, _, _) -> + Matched; +double_match_exclude(_, [], Matched, _, _) -> + Matched; +%% exclude it +double_match_exclude([V2|T1], CIn, Matched, V1, V2) -> + double_match_exclude(T1, CIn, Matched, V1, V2); +%% exclude it +double_match_exclude(COut, [V1|T2], Matched, V1, V2) -> + double_match_exclude(COut, T2, Matched, V1, V2); +%% Found match +double_match_exclude([H|T1], [H|T2], Matched, V1, V2) -> + double_match_exclude(T1, T2, [[V1,H,V2] | Matched], V1, V2); +double_match_exclude([H1|T1], [H2|T2], Matched, V1, V2) when H1 > H2 -> + double_match_exclude([H1|T1], T2, Matched, V1, V2); +double_match_exclude([_H1|T1], [H2|T2], Matched, V1, V2) -> + double_match_exclude(T1, [H2|T2], Matched, V1, V2). + + +digraph_match(OutV, V2, V1, DG) -> + digraph_match(OutV, V2, V1, DG, [], 0). + +digraph_match(OutV, V2, V1, DG, Counter) -> + digraph_match(OutV, V2, V1, DG, [], Counter). + +digraph_match([], _, _, _, _, Counter) when Counter < 2 -> + false; +digraph_match([], _, _, _, Acc, _) -> + Acc; +digraph_match([Vin|T], Vin, Vout, DG, Acc, Counter) -> + digraph_match(T, Vin, Vout, DG, Acc, Counter); +digraph_match([H|T], Vin, Vout, DG, Acc, Counter) -> + case get_path(DG, H, Vin, H, Vout) of + false -> + digraph_match(T, Vin, Vout, DG, Acc, Counter); + Path -> + %% Found one path; now me must se if there are one more. + digraph_match(T, Vin, Vout, DG, [[Vout|lists:reverse(Path)] | Acc], + Counter+1) + end. + +get_path(G, V1, V2, E1, E2) -> + one_path(digraph:out_neighbours(G, V1), V2, [], [V1], [V1], G, E1, E2). + +one_path([E1|_Vs], W, Cont, Xs, Ps, G, E1, E2) -> + one_path([], W, Cont, Xs, Ps, G, E1, E2); +one_path([E2|_Vs], W, Cont, Xs, Ps, G, E1, E2) -> + one_path([], W, Cont, Xs, Ps, G, E1, E2); +one_path([W|_Ws], W, _Cont, _Xs, Ps, _G, _E1, _E2) -> + [W|Ps]; +one_path([V|Vs], W, Cont, Xs, Ps, G, E1, E2) -> + case lists:member(V, Xs) of + true -> one_path(Vs, W, Cont, Xs, Ps, G, E1, E2); + false -> one_path(digraph:out_neighbours(G, V), W, + [{Vs,Ps} | Cont], [V|Xs], [V|Ps], G, E1, E2) + end; +one_path([], W, [{Vs,Ps}|Cont], Xs, _, G, E1, E2) -> + one_path(Vs, W, Cont, Xs, Ps, G, E1, E2); +one_path([], _, [], _, _, _, _, _) -> false. + +%%---------------------------------------------------------------------% +%% function : type_check +%% Arguments: Obj - objectrefernce to test. +%% Mod - Module which contains typeID/0. +%% Returns : 'ok' or raises exception. +%% Effect : +%%---------------------------------------------------------------------- +type_check(Obj, Mod) -> + case catch corba_object:is_a(Obj,Mod:typeID()) of + true -> + ok; + What -> + orber:dbg("[~p] CosEventDomainAdmin:type_check();~n" + "Object of incorrect type supplied; should be: ~p~n" + "Failed due to: ~p", [?LINE, Mod, What], ?DEBUG_LEVEL), + corba:raise(#'BAD_PARAM'{minor=507, completion_status=?COMPLETED_NO}) + end. + +%%---------------------------------------------------------------------% +%% function : lookup_channel +%% Arguments: DG - digraph reference +%% Id - CosEventDomainAdmin::MemberID (long()) +%% Returns : CosNotifyChannelAdmin::EventChannel | +%% {'EXCEPTION', #'CosNotifyChannelAdmin_ChannelNotFound'{}} +%% Effect : +%%---------------------------------------------------------------------- +lookup_channel(DG, Id) -> + case digraph:vertex(DG, Id) of + {Id, Channel} -> + Channel; + false -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}) + end. + + +%%---------------------------------------------------------------------% +%% function : lookup_connection +%% Arguments: DG - digraph reference +%% Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : #connectio{} | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} +%% Effect : +%%---------------------------------------------------------------------- +lookup_connection(DG, Id) -> + case digraph:edge(DG, Id) of + {Id, _SId, _CId, Connection} -> + Connection; + false -> + corba:raise(#'CosEventDomainAdmin_ConnectionNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% function : lookup_connection_data +%% Arguments: DG - digraph reference +%% Id - CosEventDomainAdmin::ConnectionID (long()) +%% Returns : CosEventDomainAdmin::Connection | +%% {'EXCEPTION', #'CosEventDomainAdmin_ConnectionNotFound'{}} +%% Effect : +%%---------------------------------------------------------------------- +lookup_connection_data(DG, Id) -> + case digraph:edge(DG, Id) of + {Id, _SId, _CId, #connection{data = Connection}} -> + Connection; + false -> + corba:raise(#'CosEventDomainAdmin_ConnectionNotFound'{}) + end. + +%%---------------------------------------------------------------------% +%% function : close_connections +%% Arguments: DG -digraph reference +%% [CosEventDomainAdmin::ConnectionID] - [long()] +%% Returns : ok +%% Effect : +%%---------------------------------------------------------------------- +close_connections(_DG, []) -> + ok; +close_connections(DG, [H|T]) -> + #connection{supplier=S, consumer=C, data=Connection} = + lookup_connection(DG, H), + close_connection(Connection, S, C), + digraph:del_edge(DG, H), + close_connections(DG, T). + +%%---------------------------------------------------------------------% +%% function : close_connection +%% Arguments: CosEventDomainAdmin::Connection +%% S - SupplierProxy +%% C - ConsumerProxy +%% Returns : ok +%% Effect : +%%---------------------------------------------------------------------- +close_connection(#'CosEventDomainAdmin_Connection'{ctype=Type, + notification_style = Style}, + S, C) -> + case {Type, Style} of + {'ANY_EVENT', 'Push'} -> + catch 'CosNotifyChannelAdmin_ProxyPushSupplier':disconnect_push_supplier(S), + catch 'CosNotifyChannelAdmin_ProxyPushConsumer':disconnect_push_consumer(C); + {'ANY_EVENT', 'Pull'} -> + catch 'CosNotifyChannelAdmin_ProxyPullSupplier':disconnect_pull_supplier(S), + catch 'CosNotifyChannelAdmin_ProxyPullConsumer':disconnect_pull_consumer(C); + {'STRUCTURED_EVENT', 'Push'} -> + catch 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':disconnect_structured_push_supplier(S), + catch 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':disconnect_structured_push_consumer(C); + {'STRUCTURED_EVENT', 'Pull'} -> + catch 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':disconnect_structured_pull_supplier(S), + catch 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':disconnect_structured_pull_consumer(C); + {'SEQUENCE_EVENT', 'Push'} -> + catch 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':disconnect_sequence_push_supplier(S), + catch 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':disconnect_sequence_push_consumer(C); + {'SEQUENCE_EVENT', 'Pull'}-> + catch 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':disconnect_sequence_pull_supplier(S), + catch 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':disconnect_sequence_pull_consumer(C) + end, + ok. + +%%---------------------------------------------------------------------% +%% function : setup_connection +%% Arguments: CosEventDomainAdmin::Connection +%% S - SupplierProxy +%% C - ConsumerProxy +%% Returns : {ok, SupplierProxy, ConsumerProxy}; +%% Effect : +%%---------------------------------------------------------------------- +setup_connection(#'CosEventDomainAdmin_Connection'{ctype=Type, + notification_style = Style}, + S, C) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(S), + case Style of + 'Push' -> + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_push_supplier(Admin, Type), + CProxy = connect_a_push_supplier(C, Proxy, Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPushSupplier': + connect_any_push_consumer(Proxy, CProxy); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPushSupplier': + connect_structured_push_consumer(Proxy, CProxy); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPushSupplier': + connect_sequence_push_consumer(Proxy, CProxy) + end, + {ok, Proxy, CProxy}; + 'Pull' -> + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin': + obtain_notification_pull_supplier(Admin, Type), + CProxy = connect_a_pull_supplier(C, Proxy, Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPullSupplier': + connect_any_pull_consumer(Proxy, CProxy); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPullSupplier': + connect_structured_pull_consumer(Proxy, CProxy); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPullSupplier': + connect_sequence_pull_consumer(Proxy, CProxy) + end, + {ok, Proxy, CProxy} + end. + +%%---------------------------------------------------------------------% +%% function : connect_a_pull_consumer +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PullConsumer +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_pull_consumer(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_pull_consumer(Channel, PC, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_pull_supplier(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPullSupplier':connect_any_pull_consumer(Proxy, PC); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPullSupplier':connect_structured_pull_consumer(Proxy, PC); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPullSupplier':connect_sequence_pull_consumer(Proxy, PC) + end, + Proxy. + +%%---------------------------------------------------------------------% +%% function : connect_a_push_consumer +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PushConsumer +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_push_consumer(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_push_consumer(Channel, PC, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_consumer_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_ConsumerAdmin':obtain_notification_push_supplier(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPushSupplier':connect_any_push_consumer(Proxy, PC); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPushSupplier':connect_structured_push_consumer(Proxy, PC); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPushSupplier':connect_sequence_push_consumer(Proxy, PC) + end, + Proxy. + +%%---------------------------------------------------------------------% +%% function : connect_a_pull_supplier +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PullSupplier +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_pull_supplier(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_pull_supplier(Channel, PS, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_supplier_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_pull_consumer(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPullConsumer':connect_any_pull_supplier(Proxy, PS); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPullConsumer':connect_structured_pull_supplier(Proxy, PS); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPullConsumer':connect_sequence_pull_supplier(Proxy, PS) + end, + Proxy. + +%%---------------------------------------------------------------------% +%% function : connect_a_push_supplier +%% Arguments: Channel - CosNotifyChannelAdmin::EventChannel | undefined +%% PC - a PushSupplier +%% Type - 'ANY_EVENT' | 'STRUCTURED_EVENT' | 'SEQUENCE_EVENT' +%% Returns : +%% Effect : +%%---------------------------------------------------------------------- +connect_a_push_supplier(undefined, _, _) -> + corba:raise(#'CosNotifyChannelAdmin_ChannelNotFound'{}); +connect_a_push_supplier(Channel, PS, Type) -> + Admin = + 'CosNotifyChannelAdmin_EventChannel':'_get_default_supplier_admin'(Channel), + {Proxy, _Id} = + 'CosNotifyChannelAdmin_SupplierAdmin':obtain_notification_push_consumer(Admin, + Type), + case Type of + 'ANY_EVENT' -> + 'CosNotifyChannelAdmin_ProxyPushConsumer':connect_any_push_supplier(Proxy, PS); + 'STRUCTURED_EVENT' -> + 'CosNotifyChannelAdmin_StructuredProxyPushConsumer':connect_structured_push_supplier(Proxy, PS); + 'SEQUENCE_EVENT' -> + 'CosNotifyChannelAdmin_SequenceProxyPushConsumer':connect_sequence_push_supplier(Proxy, PS) + end, + Proxy. + + +%%====================================================================== +%% END OF MODULE +%%====================================================================== + |