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