[Release] wrt-plugins-common_0.3.104
[platform/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/secure_log.h>
31 #include <Commons/ThreadPool.h>
32
33 namespace WrtDeviceApis {
34 namespace Commons {
35 template<class TemplateEvent>
36 class SignalEventCall : public DPL::Event::AbstractEventCall
37 {
38     DPL::SharedPtr<TemplateEvent> m_event;
39
40   public:
41
42     SignalEventCall(const DPL::SharedPtr<TemplateEvent> &event) : m_event(event)
43     {}
44     virtual void Call()
45     {
46         _D("signaling in SignalEventCall");
47         m_event->signalSynchronousEventFlag();
48     }
49 };
50
51 template<class TemplateEvent>
52 class EventReceiver :
53     protected DPL::Event::Controller<
54         typename DPL::TypeListDecl<DPL::SharedPtr<TemplateEvent> >::Type>
55 {
56     DPL::Event::ThreadEventDispatcher m_threadDispatcher;
57
58   protected:
59
60     EventReceiver(ThreadEnum::Enumeration threadType)
61     {
62         DPL::Thread *thread =
63             ThreadPool::getInstance().getThreadRef(threadType);
64         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
65             Touch();
66         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
67             SwitchToThread(thread);
68     }
69
70     void signalEventByDispatcher(const DPL::SharedPtr<TemplateEvent> &event)
71     {
72         _D("called");
73         Try {
74             DPL::Event::AbstractEventDispatcher *dispatcher =
75                 ThreadPool::getInstance().getDispatcher(m_threadDispatcher);
76             dispatcher->AddEventCall(new SignalEventCall<TemplateEvent>(event));
77         }
78         Catch(DPL::Thread::Exception::UnmanagedThread) {
79             // if called on unmanaged thread,
80             // call signalSynchronousEventFlag() directly
81             _E("signalSynchronousEventFlag() is called"
82                      "by unmanaged thread");
83             event->signalSynchronousEventFlag();
84         }
85     }
86
87     virtual ~EventReceiver()
88     {
89         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
90             SwitchToThread(NULL);
91     }
92 };
93
94 template<class TemplateEvent>
95 class EventRequestReceiver : private EventReceiver<TemplateEvent>
96 {
97   public:
98     EventRequestReceiver(ThreadEnum::Enumeration threadType) : EventReceiver<
99             TemplateEvent>(threadType)
100     {}
101     virtual void OnRequestReceived(const DPL::SharedPtr<TemplateEvent> &event)
102         = 0;
103
104     /*
105      *
106      * @argument delaySeconds - event will be received not sooner than after
107      * delay (in seconds)
108      */
109     void PostRequest(const DPL::SharedPtr<TemplateEvent> &event,
110                      double delaySeconds = 0.0)
111     {
112         _D("called");
113         {
114             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
115             assert(TemplateEvent::STATE_INITIAL == event->m_state);
116             event->m_state = TemplateEvent::STATE_REQUEST_SEND;
117         }
118
119         if (TemplateEvent::HANDLING_SYNCHRONOUS == event->getHandlingType() &&
120             !event->m_synchronousEventFlag)
121         {
122             event->m_synchronousEventFlag = new DPL::WaitableEvent();
123         }
124
125         if (0.0 == delaySeconds) {
126             DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >
127                 ::
128                 PostEvent(event);
129         } else {
130             DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >
131                 ::
132                 PostTimedEvent(event, delaySeconds);
133         }
134
135         switch (event->getHandlingType()) {
136         case TemplateEvent::HANDLING_NOT_SET:
137             assert(0);
138             break;
139         case TemplateEvent::HANDLING_SYNCHRONOUS:
140             event->waitForAnswer();
141             break;
142         }
143     }
144
145     void OnEventReceived(const DPL::SharedPtr<TemplateEvent> &event)
146     {
147         _D("called");
148         {
149             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
150             if (event->m_cancelled) {
151                 event->handleCancel();
152                 event->m_cancelAllowed = true;
153                 event->signalCancelStatusFlag();
154                 event->signalFinishedFlag();
155                 return;
156             } else {
157                 assert(
158                     TemplateEvent::STATE_REQUEST_SEND == event->m_state &&
159                     "Wrong state!");
160             }
161             event->m_state = TemplateEvent::STATE_REQUEST_RECEIVED;
162         }
163
164         OnRequestReceived(event);
165         event->signalCancelStatusFlag();
166         //After Controller ends processing it should call it to signal that work
167         // is done
168         {
169             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
170
171             if (event->m_cancelled) {
172                 //if cancel was not handled in OnRequestReceived when we should
173                 //process as if it was not cancelled at all.
174                 if (event->m_cancelAllowed) {
175                     event->handleCancel();
176                     event->signalFinishedFlag();
177                     return;
178                 }
179             }
180             //when event is not in manual answer mode we will answer now
181             if (TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER !=
182                 event->m_handlingType &&
183                 TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER !=
184                 event->m_handlingType)
185             {
186                 event->m_state = TemplateEvent::STATE_ANSWER_SEND;
187             }
188         }
189
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             this->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             this->signalEventByDispatcher(event);
205             break;
206         //when event is in manual answer mode we do nothing - the answer will be
207         // send explicit from the code
208         case TemplateEvent::HANDLING_SYNCHRONOUS_MANUAL_ANSWER:
209         case TemplateEvent::HANDLING_ASYNCHRONOUS_MANUAL_ANSWER:
210             break;
211         }
212     }
213
214     virtual void ManualAnswer(const DPL::SharedPtr<TemplateEvent> &event)
215     {
216         _D("called");
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             this->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             this->signalEventByDispatcher(event);
247             break;
248         default:
249             break;
250         }
251     }
252 };
253
254 template<class TemplateEvent>
255 class EventAnswerReceiver : private EventReceiver<TemplateEvent>
256 {
257   public:
258     EventAnswerReceiver(ThreadEnum::Enumeration threadType) : EventReceiver<
259             TemplateEvent>(threadType)
260     {}
261
262     virtual void OnAnswerReceived(const DPL::SharedPtr<TemplateEvent> &event) =
263         0;
264
265     //it should be hidden outside, but I can't do it! I can't! :|
266     void PostAnswer(const DPL::SharedPtr<TemplateEvent> &event)
267     {
268         LogDebug(__FUNCTION__);
269         event->signalCancelStatusFlag();
270         DPL::Event::ControllerEventHandler<DPL::SharedPtr<TemplateEvent> >::
271             PostEvent(
272             event);
273     }
274
275     void OnEventReceived(const DPL::SharedPtr<TemplateEvent> &event)
276     {
277         _D("EventAnswerReceiver: answer received");
278         //check if it can be processed and set the state
279         {
280             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
281
282             //in case someone changed it to synchronous call, we don't process
283             // it
284             if (TemplateEvent::STATE_CHANGED_TO_SYNCHRONOUS ==
285                 event->m_state || TemplateEvent::STATE_ENDED ==
286                 event->m_state)
287             {
288                 return;
289             }
290             //we should get cancelled or answer_send state here
291             assert(
292                 TemplateEvent::STATE_ANSWER_SEND == event->m_state &&
293                 "Wrong state!");
294
295             if (event->m_cancelled && event->m_cancelAllowed) {
296                 event->handleCancel();
297                 event->signalFinishedFlag();
298                 return;
299             }
300             event->m_state = TemplateEvent::STATE_ANSWER_RECEIVED;
301         }
302
303         OnAnswerReceived(event);
304
305         {
306             DPL::Mutex::ScopedLock lock(&event->m_stateMutex);
307             assert(TemplateEvent::STATE_ANSWER_RECEIVED == event->m_state);
308             event->m_state = TemplateEvent::STATE_ENDED;
309             delete event->m_cancelStatusFlag;
310             event->m_cancelStatusFlag = NULL;
311             //if someone is waiting
312             event->signalFinishedFlag();
313         }
314     }
315 };
316 }
317 } // WrtDeviceApisCommon
318
319 #endif /* WRTDEVICEAPIS_COMMONS_EVENT_RECEIVER_H_ */