tizen beta release
[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         DPL::Event::AbstractEventDispatcher *dispatcher =
75             ThreadPool::getInstance().getDispatcher(m_threadDispatcher);
76         dispatcher->AddEventCall(new SignalEventCall<TemplateEvent>(event));
77     }
78
79     virtual ~EventReceiver()
80     {
81         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
82             SwitchToThread(NULL);
83     }
84 };
85
86
87 template<class TemplateEvent>
88 class EventRequestReceiver : private EventReceiver<TemplateEvent>
89 {
90   public:
91     EventRequestReceiver(ThreadEnum::Enumeration threadType) : EventReceiver<
92             TemplateEvent>(threadType)
93     {
94     }
95     virtual void OnRequestReceived(const DPL::SharedPtr<TemplateEvent> &event)
96         = 0;
97
98     /*
99      *
100      * @argument delaySeconds - event will be received not sooner than after delay (in seconds)
101      */
102     void PostRequest(const DPL::SharedPtr<TemplateEvent> &event,
103             double delaySeconds = 0.0)
104     {
105         LogDebug(__FUNCTION__);
106         {
107             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
108             assert(TemplateEvent::STATE_INITIAL == event->m_state);
109             event->m_state = TemplateEvent::STATE_REQUEST_SEND;
110         }
111         LogDebug("state changed to STATE_REQUEST_SEND. Now posting");
112
113         if (TemplateEvent::HANDLING_SYNCHRONOUS == event->getHandlingType() &&
114             !event->m_synchronousEventFlag) {
115             event->m_synchronousEventFlag = new DPL::WaitableEvent();
116         }
117
118         if (0.0 == delaySeconds) {
119             DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
120                 PostEvent(event);
121         } else {
122             DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
123                 PostTimedEvent(event, delaySeconds);
124         }
125         LogDebug("Event posted.");
126         switch (event->getHandlingType()) {
127         case TemplateEvent::HANDLING_NOT_SET:
128             assert(0);
129             break;
130         case TemplateEvent::HANDLING_SYNCHRONOUS:
131             LogDebug("It's synchronous call - waiting for answer...");
132             event->waitForAnswer();
133             LogDebug("...answer received");
134             break;
135         }
136     }
137
138     void OnEventReceived(const DPL::SharedPtr<TemplateEvent> &event)
139     {
140         LogDebug(__FUNCTION__);
141         {
142             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
143             if (event->m_cancelled) {
144                 event->handleCancel();
145                 event->m_cancelAllowed = true;
146                 event->signalCancelStatusFlag();
147                 event->signalFinishedFlag();
148                 return;
149             } else {
150                 assert(
151                     TemplateEvent::STATE_REQUEST_SEND == event->m_state &&
152                     "Wrong state!");
153             }
154             event->m_state = TemplateEvent::STATE_REQUEST_RECEIVED;
155         }
156         LogDebug("calling OnRequestReceived");
157         OnRequestReceived(event);
158         event->signalCancelStatusFlag();
159         //After Controller ends processing it should call it to signal that work is done
160         {
161             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
162
163             if (event->m_cancelled) {
164                 //if cancel was not handled in OnRequestReceived when we should
165                 //process as if it was not cancelled at all.
166                 if (event->m_cancelAllowed) {
167                     event->handleCancel();
168                     event->signalFinishedFlag();
169                     return;
170                 }
171             }
172             //when event is not in manual answer mode we will answer now
173             if (TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER !=
174                 event->m_handlingType &&
175                 TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER !=
176                 event->m_handlingType) {
177                 event->m_state = TemplateEvent::STATE_ANSWER_SEND;
178             }
179         }
180         LogDebug("choosing the answer method");
181         switch (event->m_handlingType) {
182         case TemplateEvent::HANDLING_NOT_SET:
183             assert(0);
184             break;
185         case TemplateEvent::HANDLING_SYNCHRONOUS:
186             //event->Signal();
187             signalEventByDispatcher(event);
188             break;
189         case TemplateEvent::HANDLING_ASYNCHRONOUS:
190             ///TODO check - shouldn't it be in signalEventByDispatcher?
191             if (NULL != event->m_remoteController) {
192                 event->m_remoteController->PostAnswer(event);
193             }
194             //event->Signal();
195             signalEventByDispatcher(event);
196             break;
197         //when event is in manual answer mode we do nothing - the answer will be send explicit from the code
198         case TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER:
199         case TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER:
200             LogDebug("Manual answer is set so do nothing.");
201             break;
202         }
203     }
204
205     virtual void ManualAnswer(const DPL::SharedPtr<TemplateEvent> &event)
206     {
207         LogDebug(__FUNCTION__);
208         assert(
209             event->m_handlingType ==
210             TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER ||
211             event->m_handlingType ==
212             TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER);
213         {
214             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
215             if (event->m_cancelled) {
216                 //if cancel was not handled in OnRequestReceived when we should
217                 //process as if it was not cancelled at all.
218                 if (event->m_cancelAllowed) {
219                     event->handleCancel();
220                     event->signalCancelStatusFlag();
221                     event->signalFinishedFlag();
222                     return;
223                 }
224             }
225             event->m_state = TemplateEvent::STATE_ANSWER_SEND;
226         }
227         switch (event->m_handlingType) {
228         case TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER:
229             //event->Signal();
230             signalEventByDispatcher(event);
231             break;
232         case TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER:
233             //event->Signal();
234             if (NULL != event->m_remoteController) {
235                 event->m_remoteController->PostAnswer(event);
236             }
237             signalEventByDispatcher(event);
238             break;
239         default:
240             break;
241         }
242     }
243 };
244
245
246 template<class TemplateEvent>
247 class EventAnswerReceiver : private EventReceiver<TemplateEvent>
248 {
249   public:
250     EventAnswerReceiver(ThreadEnum::Enumeration threadType) : EventReceiver<
251             TemplateEvent>(threadType)
252     {
253     }
254
255     virtual void OnAnswerReceived(const DPL::SharedPtr<TemplateEvent> &event) =
256         0;
257
258     //it should be hidden outside, but I can't do it! I can't! :|
259     void PostAnswer(const DPL::SharedPtr<TemplateEvent> &event)
260     {
261         LogDebug(__FUNCTION__);
262         event->signalCancelStatusFlag();
263         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::PostEvent(
264             event);
265     }
266
267     void OnEventReceived(const DPL::SharedPtr<TemplateEvent> &event)
268     {
269         LogDebug("EventAnswerReceiver: answer received");
270         //check if it can be processed and set the state
271         {
272             LogDebug("checking the state");
273             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
274
275             //in case someone changed it to synchronous call, we don't process it
276             if (TemplateEvent::STATE_CHANGED_TO_SYNCHRONOUS ==
277                 event->m_state || TemplateEvent::STATE_ENDED ==
278                 event->m_state) {
279                 LogDebug(
280                     "Handling probably changed to synchronous meanwhile. Will not process it..");
281                 return;
282             }
283             //we should get cancelled or answer_send state here
284             assert(
285                 TemplateEvent::STATE_ANSWER_SEND == event->m_state &&
286                 "Wrong state!");
287
288             if (event->m_cancelled && event->m_cancelAllowed) {
289                 event->handleCancel();
290                 event->signalFinishedFlag();
291                 return;
292             }
293             event->m_state = TemplateEvent::STATE_ANSWER_RECEIVED;
294         }
295         LogDebug("calling OnAnswerReceived");
296         OnAnswerReceived(event);
297
298         LogDebug("changing the state");
299         {
300             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
301             assert(TemplateEvent::STATE_ANSWER_RECEIVED == event->m_state);
302             event->m_state = TemplateEvent::STATE_ENDED;
303             delete event->m_cancelStatusFlag;
304             event->m_cancelStatusFlag = NULL;
305             //if someone is waiting
306             event->signalFinishedFlag();
307         }
308         LogDebug("leaving");
309     }
310 };
311
312 }
313 } // WrtDeviceApisCommon
314
315 #endif /* WRTDEVICEAPIS_COMMONS_EVENT_RECEIVER_H_ */