1%%--------------------------------------------------------------------
2%%
3%% %CopyrightBegin%
4%%
5%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
6%%
7%% Licensed under the Apache License, Version 2.0 (the "License");
8%% you may not use this file except in compliance with the License.
9%% You may obtain a copy of the License at
10%%
11%%     http://www.apache.org/licenses/LICENSE-2.0
12%%
13%% Unless required by applicable law or agreed to in writing, software
14%% distributed under the License is distributed on an "AS IS" BASIS,
15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16%% See the License for the specific language governing permissions and
17%% limitations under the License.
18%%
19%% %CopyrightEnd%
20%%
21%%
22%%----------------------------------------------------------------------
23%% File        : oe_CosEventComm_Channel_impl.erl
24%% Description :
25%%
26%%----------------------------------------------------------------------
27-module(oe_CosEventComm_Channel_impl).
28
29%%----------------------------------------------------------------------
30%% Include files
31%%----------------------------------------------------------------------
32-include_lib("orber/include/corba.hrl").
33-include("cosEventApp.hrl").
34
35
36%%----------------------------------------------------------------------
37%% External exports
38%%----------------------------------------------------------------------
39%% Mandatory
40-export([init/1,
41	 terminate/2,
42	 code_change/3,
43         handle_info/2]).
44
45%% Exports from "CosEventChannelAdmin::EventChannel"
46-export([for_consumers/3,
47	 for_suppliers/3,
48	 destroy/3]).
49
50
51%%----------------------------------------------------------------------
52%% Internal exports
53%%----------------------------------------------------------------------
54%% Exports from "oe_CosEventComm::Event"
55-export([send/3, send_sync/4]).
56
57%%----------------------------------------------------------------------
58%% Records
59%%----------------------------------------------------------------------
60-record(state, {typecheck, pull_interval, maxevents, blocking, cadmins = [],
61		server_options}).
62
63%%----------------------------------------------------------------------
64%% Macros
65%%----------------------------------------------------------------------
66
67%%======================================================================
68%% External functions
69%%======================================================================
70%%----------------------------------------------------------------------
71%% Function   : init/1
72%% Returns    : {ok, State}          |
73%%              {ok, State, Timeout} |
74%%              ignore               |
75%%              {stop, Reason}
76%% Description: Initiates the server
77%%----------------------------------------------------------------------
78init([Options, ServerOpts]) ->
79    process_flag(trap_exit, true),
80    PullI = cosEventApp:get_option(?PULL_INTERVAL, Options),
81    TC = cosEventApp:get_option(?TYPECHECK, Options),
82    Max = cosEventApp:get_option(?MAXEVENTS, Options),
83    Blocking = cosEventApp:get_option(?BLOCKING, Options),
84    {ok, #state{typecheck = TC, pull_interval = PullI, maxevents = Max,
85		blocking = Blocking, server_options = ServerOpts}}.
86
87%%----------------------------------------------------------------------
88%% Function   : terminate/2
89%% Returns    : any (ignored by gen_server)
90%% Description: Shutdown the server
91%%----------------------------------------------------------------------
92terminate(_Reason, _State) ->
93    ?DBG("Terminating ~p~n", [_Reason]),
94    ok.
95
96%%----------------------------------------------------------------------
97%% Function   : code_change/3
98%% Returns    : {ok, NewState}
99%% Description: Convert process state when code is changed
100%%----------------------------------------------------------------------
101code_change(_OldVsn, State, _Extra) ->
102    {ok, State}.
103
104%%---------------------------------------------------------------------%
105%% function : handle_info
106%% Arguments:
107%% Returns  : {noreply, State} |
108%%            {stop, Reason, State}
109%% Effect   : Functions demanded by the gen_server module.
110%%----------------------------------------------------------------------
111handle_info({'EXIT', Pid, _Reason}, #state{cadmins = CAdmins} = State) ->
112    ?DBG("Probably a child terminated with Reason: ~p~n", [_Reason]),
113    {noreply, State#state{cadmins = lists:keydelete(Pid, 2, CAdmins)}};
114handle_info(_Info, State) ->
115    ?DBG("Unknown Info ~p~n", [_Info]),
116    {noreply, State}.
117
118
119%%----------------------------------------------------------------------
120%% Function   : for_consumers
121%% Arguments  :
122%% Returns    :
123%% Description:
124%%----------------------------------------------------------------------
125for_consumers(_, _, #state{server_options = ServerOpts} = State) ->
126    case catch 'oe_CosEventComm_CAdmin':oe_create_link([self(),
127							State#state.typecheck,
128							State#state.maxevents,
129							ServerOpts],
130						       [{sup_child, true}|ServerOpts]) of
131	{ok, Pid, AdminCo} ->
132	    ?DBG("Created a new oe_CosEventComm_CAdmin.~n", []),
133	    {reply, AdminCo,
134	     State#state{cadmins = [{AdminCo, Pid}|State#state.cadmins]}};
135	Other ->
136	    orber:dbg("[~p] oe_CosEventComm_Channel:for_consumers(); Error: ~p",
137		      [?LINE, Other], ?DEBUG_LEVEL),
138	    corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
139    end.
140
141%%----------------------------------------------------------------------
142%% Function   : for_suppliers
143%% Arguments  :
144%% Returns    :
145%% Description:
146%%----------------------------------------------------------------------
147for_suppliers(OE_This, _, #state{server_options = ServerOpts} = State) ->
148    case catch 'CosEventChannelAdmin_SupplierAdmin':oe_create_link([OE_This, self(),
149								    State#state.typecheck,
150								    State#state.pull_interval,
151								    ServerOpts],
152								   [{sup_child, true}|ServerOpts]) of
153	{ok, _Pid, AdminSu} ->
154	    ?DBG("Created a new CosEventChannelAdmin_SupplierAdmin.~n", []),
155	    {reply, AdminSu, State};
156	Other ->
157	    orber:dbg("[~p] oe_CosEventComm_Channel:for_suppliers();~nError: ~p",
158		      [?LINE, Other], ?DEBUG_LEVEL),
159	    corba:raise(#'INTERNAL'{completion_status=?COMPLETED_NO})
160    end.
161
162%%----------------------------------------------------------------------
163%% Function   : destroy
164%% Arguments  :
165%% Returns    :
166%% Description:
167%%----------------------------------------------------------------------
168destroy(_, _, State) ->
169    ?DBG("Destroy invoked.", []),
170    {stop, normal, ok, State}.
171
172%%----------------------------------------------------------------------
173%% Function   : send
174%% Arguments  :
175%% Returns    :
176%% Description:
177%%----------------------------------------------------------------------
178send(_OE_This, #state{cadmins = CAdmins} = State, Any) ->
179    ?DBG("Received Event ~p~n", [Any]),
180    case send_helper(CAdmins, Any, [], false) of
181	ok ->
182	    ?DBG("Received Event and forwarded it successfully.~n", []),
183	    {noreply, State};
184	{error, Dropped} ->
185	    ?DBG("Received Event but forward failed for: ~p~n", [Dropped]),
186	    RemainingAdmins = delete_cadmin(Dropped, CAdmins),
187	    {noreply, State#state{cadmins = RemainingAdmins}}
188    end.
189
190%%----------------------------------------------------------------------
191%% Function   : send_sync
192%% Arguments  :
193%% Returns    :
194%% Description:
195%%----------------------------------------------------------------------
196send_sync(_OE_This, OE_From, #state{cadmins = CAdmins, blocking = BL} = State, Any) ->
197    ?DBG("Received Event ~p~n", [Any]),
198    corba:reply(OE_From, ok),
199    case send_helper(CAdmins, Any, [], BL) of
200	ok ->
201	    ?DBG("Received Event and forwarded (sync) it successfully.~n", []),
202	    {reply, ok, State};
203	{error, Dropped} ->
204	    ?DBG("Received Event but forward (sync) failed for: ~p~n", [Dropped]),
205	    RemainingAdmins = delete_cadmin(Dropped, CAdmins),
206	    {reply, ok, State#state{cadmins = RemainingAdmins}}
207    end.
208
209
210%%======================================================================
211%% Internal functions
212%%======================================================================
213send_helper([], _, [], _) ->
214    ok;
215send_helper([], _, Dropped, _) ->
216    {error, Dropped};
217send_helper([{ObjRef, Pid}|T], Event, Dropped, false) ->
218    case catch 'oe_CosEventComm_CAdmin':send(ObjRef, Event) of
219	ok ->
220	    send_helper(T, Event, Dropped, false);
221	What ->
222	    orber:dbg("[~p] oe_CosEventComm_Channel:send_helper(~p, ~p);~n"
223		      "Bad return value ~p. Closing connection.",
224		      [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL),
225	    send_helper(T, Event, [{ObjRef, Pid}|Dropped], false)
226    end;
227send_helper([{ObjRef, Pid}|T], Event, Dropped, Sync) ->
228    case catch 'oe_CosEventComm_CAdmin':send_sync(ObjRef, Event) of
229	ok ->
230	    send_helper(T, Event, Dropped, Sync);
231	What ->
232	    orber:dbg("[~p] oe_CosEventComm_Channel:send_helper(~p, ~p);~n"
233		      "Bad return value ~p. Closing connection.",
234		      [?LINE, ObjRef, Event, What], ?DEBUG_LEVEL),
235	    send_helper(T, Event, [{ObjRef, Pid}|Dropped], Sync)
236    end.
237
238
239delete_cadmin([], RemainingAdmins) ->
240    RemainingAdmins;
241delete_cadmin([{_,Pid}|T], CAdmins) ->
242    Rest = lists:keydelete(Pid, 2, CAdmins),
243    delete_cadmin(T, Rest).
244
245%%======================================================================
246%% END OF MODULE
247%%======================================================================
248