Update wrt-plugins-common_0.3.53
[framework/web/wrt-plugins-common.git] / src / Commons / EventReceiver.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @author      Karol Majewski (k.majewski@samsung.com)
18  * @version     0.1
19  * @brief
20  */
21 #ifndef WRTDEVICEAPIS_COMMONS_EVENT_RECEIVER_H_
22 #define WRTDEVICEAPIS_COMMONS_EVENT_RECEIVER_H_
23
24 #include <assert.h>
25 #include <dpl/event/thread_event_dispatcher.h>
26 #include <dpl/shared_ptr.h>
27 #include <dpl/event/controller.h>
28 #include <dpl/type_list.h>
29 #include <dpl/event/abstract_event_call.h>
30 #include <dpl/log/log.h>
31 #include <Commons/ThreadPool.h>
32
33 namespace WrtDeviceApis {
34 namespace Commons {
35
36 template<class TemplateEvent>
37 class SignalEventCall : public DPL::Event::AbstractEventCall
38 {
39     DPL::SharedPtr<TemplateEvent> m_event;
40   public:
41
42     SignalEventCall(const DPL::SharedPtr<TemplateEvent> &event) : m_event(event)
43     {
44     }
45     virtual void Call()
46     {
47         LogDebug("signaling in SignalEventCall");
48         m_event->signalSynchronousEventFlag();
49     }
50 };
51
52
53 template<class TemplateEvent>
54 class EventReceiver :
55     protected DPL::Event::Controller<
56         typename DPL::TypeListDecl<DPL::SharedPtr<TemplateEvent> >::Type>
57 {
58     DPL::Event::ThreadEventDispatcher m_threadDispatcher;
59   protected:
60
61     EventReceiver(ThreadEnum::Enumeration threadType)
62     {
63         DPL::Thread *thread =
64             ThreadPool::getInstance().getThreadRef(threadType);
65         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
66             Touch();
67         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
68             SwitchToThread(thread);
69     }
70
71     void signalEventByDispatcher(const DPL::SharedPtr<TemplateEvent> &event)
72     {
73         LogDebug("in");
74         Try {
75             DPL::Event::AbstractEventDispatcher *dispatcher =
76                 ThreadPool::getInstance().getDispatcher(m_threadDispatcher);
77             dispatcher->AddEventCall(new SignalEventCall<TemplateEvent>(event));
78         }
79         Catch(DPL::Thread::Exception::UnmanagedThread) {
80             // if called on unmanaged thread,
81             // call signalSynchronousEventFlag() directly
82             LogDebug("signalSynchronousEventFlag() is called"
83                      "by unmanaged thread");
84             event->signalSynchronousEventFlag();
85         }
86     }
87
88     virtual ~EventReceiver()
89     {
90         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
91             SwitchToThread(NULL);
92     }
93 };
94
95
96 template<class TemplateEvent>
97 class EventRequestReceiver : private EventReceiver<TemplateEvent>
98 {
99   public:
100     EventRequestReceiver(ThreadEnum::Enumeration threadType) : EventReceiver<
101             TemplateEvent>(threadType)
102     {
103     }
104     virtual void OnRequestReceived(const DPL::SharedPtr<TemplateEvent> &event)
105         = 0;
106
107     /*
108      *
109      * @argument delaySeconds - event will be received not sooner than after delay (in seconds)
110      */
111     void PostRequest(const DPL::SharedPtr<TemplateEvent> &event,
112             double delaySeconds = 0.0)
113     {
114         LogDebug(__FUNCTION__);
115         {
116             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
117             assert(TemplateEvent::STATE_INITIAL == event->m_state);
118             event->m_state = TemplateEvent::STATE_REQUEST_SEND;
119         }
120         LogDebug("state changed to STATE_REQUEST_SEND. Now posting");
121
122         if (TemplateEvent::HANDLING_SYNCHRONOUS == event->getHandlingType() &&
123             !event->m_synchronousEventFlag) {
124             event->m_synchronousEventFlag = new DPL::WaitableEvent();
125         }
126
127         if (0.0 == delaySeconds) {
128             DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
129                 PostEvent(event);
130         } else {
131             DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
132                 PostTimedEvent(event, delaySeconds);
133         }
134         LogDebug("Event posted.");
135         switch (event->getHandlingType()) {
136         case TemplateEvent::HANDLING_NOT_SET:
137             assert(0);
138             break;
139         case TemplateEvent::HANDLING_SYNCHRONOUS:
140             LogDebug("It's synchronous call - waiting for answer...");
141             event->waitForAnswer();
142             LogDebug("...answer received");
143             break;
144         }
145     }
146
147     void OnEventReceived(const DPL::SharedPtr<TemplateEvent> &event)
148     {
149         LogDebug(__FUNCTION__);
150         {
151             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
152             if (event->m_cancelled) {
153                 event->handleCancel();
154                 event->m_cancelAllowed = true;
155                 event->signalCancelStatusFlag();
156                 event->signalFinishedFlag();
157                 return;
158             } else {
159                 assert(
160                     TemplateEvent::STATE_REQUEST_SEND == event->m_state &&
161                     "Wrong state!");
162             }
163             event->m_state = TemplateEvent::STATE_REQUEST_RECEIVED;
164         }
165         LogDebug("calling OnRequestReceived");
166         OnRequestReceived(event);
167         event->signalCancelStatusFlag();
168         //After Controller ends processing it should call it to signal that work is done
169         {
170             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
171
172             if (event->m_cancelled) {
173                 //if cancel was not handled in OnRequestReceived when we should
174                 //process as if it was not cancelled at all.
175                 if (event->m_cancelAllowed) {
176                     event->handleCancel();
177                     event->signalFinishedFlag();
178                     return;
179                 }
180             }
181             //when event is not in manual answer mode we will answer now
182             if (TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER !=
183                 event->m_handlingType &&
184                 TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER !=
185                 event->m_handlingType) {
186                 event->m_state = TemplateEvent::STATE_ANSWER_SEND;
187             }
188         }
189         LogDebug("choosing the answer method");
190         switch (event->m_handlingType) {
191         case TemplateEvent::HANDLING_NOT_SET:
192             assert(0);
193             break;
194         case TemplateEvent::HANDLING_SYNCHRONOUS:
195             //event->Signal();
196             signalEventByDispatcher(event);
197             break;
198         case TemplateEvent::HANDLING_ASYNCHRONOUS:
199             ///TODO check - shouldn't it be in signalEventByDispatcher?
200             if (NULL != event->m_remoteController) {
201                 event->m_remoteController->PostAnswer(event);
202             }
203             //event->Signal();
204             signalEventByDispatcher(event);
205             break;
206         //when event is in manual answer mode we do nothing - the answer will be send explicit from the code
207         case TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER:
208         case TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER:
209             LogDebug("Manual answer is set so do nothing.");
210             break;
211         }
212     }
213
214     virtual void ManualAnswer(const DPL::SharedPtr<TemplateEvent> &event)
215     {
216         LogDebug(__FUNCTION__);
217         assert(
218             event->m_handlingType ==
219             TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER ||
220             event->m_handlingType ==
221             TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER);
222         {
223             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
224             if (event->m_cancelled) {
225                 //if cancel was not handled in OnRequestReceived when we should
226                 //process as if it was not cancelled at all.
227                 if (event->m_cancelAllowed) {
228                     event->handleCancel();
229                     event->signalCancelStatusFlag();
230                     event->signalFinishedFlag();
231                     return;
232                 }
233             }
234             event->m_state = TemplateEvent::STATE_ANSWER_SEND;
235         }
236         switch (event->m_handlingType) {
237         case TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER:
238             //event->Signal();
239             signalEventByDispatcher(event);
240             break;
241         case TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER:
242             //event->Signal();
243             if (NULL != event->m_remoteController) {
244                 event->m_remoteController->PostAnswer(event);
245             }
246             signalEventByDispatcher(event);
247             break;
248         default:
249             break;
250         }
251     }
252 };
253
254
255 template<class TemplateEvent>
256 class EventAnswerReceiver : private EventReceiver<TemplateEvent>
257 {
258   public:
259     EventAnswerReceiver(ThreadEnum::Enumeration threadType) : EventReceiver<
260             TemplateEvent>(threadType)
261     {
262     }
263
264     virtual void OnAnswerReceived(const DPL::SharedPtr<TemplateEvent> &event) =
265         0;
266
267     //it should be hidden outside, but I can't do it! I can't! :|
268     void PostAnswer(const DPL::SharedPtr<TemplateEvent> &event)
269     {
270         LogDebug(__FUNCTION__);
271         event->signalCancelStatusFlag();
272         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::PostEvent(
273             event);
274     }
275
276     void OnEventReceived(const DPL::SharedPtr<TemplateEvent> &event)
277     {
278         LogDebug("EventAnswerReceiver: answer received");
279         //check if it can be processed and set the state
280         {
281             LogDebug("checking the state");
282             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
283
284             //in case someone changed it to synchronous call, we don't process it
285             if (TemplateEvent::STATE_CHANGED_TO_SYNCHRONOUS ==
286                 event->m_state || TemplateEvent::STATE_ENDED ==
287                 event->m_state) {
288                 LogDebug(
289                     "Handling probably changed to synchronous meanwhile. Will not process it..");
290                 return;
291             }
292             //we should get cancelled or answer_send state here
293             assert(
294                 TemplateEvent::STATE_ANSWER_SEND == event->m_state &&
295                 "Wrong state!");
296
297             if (event->m_cancelled && event->m_cancelAllowed) {
298                 event->handleCancel();
299                 event->signalFinishedFlag();
300                 return;
301             }
302             event->m_state = TemplateEvent::STATE_ANSWER_RECEIVED;
303         }
304         LogDebug("calling OnAnswerReceived");
305         OnAnswerReceived(event);
306
307         LogDebug("changing the state");
308         {
309             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
310             assert(TemplateEvent::STATE_ANSWER_RECEIVED == event->m_state);
311             event->m_state = TemplateEvent::STATE_ENDED;
312             delete event->m_cancelStatusFlag;
313             event->m_cancelStatusFlag = NULL;
314             //if someone is waiting
315             event->signalFinishedFlag();
316         }
317         LogDebug("leaving");
318     }
319 };
320
321 }
322 } // WrtDeviceApisCommon
323
324 #endif /* WRTDEVICEAPIS_COMMONS_EVENT_RECEIVER_H_ */