%%--------------------------------------------------------------------
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2001-2011. 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, []).
%% To avoid dialyzer warnings due to the use of exit/throw.
-spec(set_qos_helper/3 :: (_, _, _) -> no_return()).
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}.
%% To avoid dialyzer warnings due to the use of exit/throw.
-spec(validate_qos_helper/4 :: (_, _, _, _) -> no_return()).
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
%%======================================================================