08d056aa459ec9ecdca4ae609d94e95265e64587
[platform/framework/web/wrt-plugins-common.git] / src / plugin-loading / plugin_logic.cpp
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  * @file        plugin_logic.cpp
18  * @author      Piotr Fatyga (p.fatyga@samsung.com)
19  * @author      Grzegorz Krawczyk (g.krawczyk@samsung.com)
20  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
21  * @version     1.0
22  * @brief       This file is the implementation file of plugin and
23  *              feature loading routines
24  * @brief       This code is intended to work behind view controller
25  */
26
27 #include "plugin_logic.h"
28
29 #include <dpl/assert.h>
30 #include <dpl/scoped_array.h>
31 #include <dpl/log/log.h>
32 #include <dpl/foreach.h>
33 #include <dpl/singleton_impl.h>
34 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
35 #include <dpl/wrt-dao-ro/common_dao_types.h>
36 #include <dpl/wrt-dao-ro/global_config.h>
37
38 #include <JavaScriptCore/JavaScript.h>
39
40 #include <string>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <dirent.h>
44 #include <errno.h>
45 #include <fstream>
46 #include <map>
47 #include <list>
48 #include <vector>
49 #include <algorithm>
50 #include <cstring>
51
52 #include <wrt_plugin_export.h>
53 #include <js_overlay_types.h>
54
55 #include "explorer.h"
56 #include "plugin.h"
57 #include "plugin_model.h"
58 #include "javascript_interface.h"
59 #include "js_function_manager.h"
60 #include "plugin_container_support.h"
61
62 #include "js_page_session.h"
63
64 using namespace std;
65 using namespace WrtDB;
66 using namespace WrtPlugins::W3C;
67
68 namespace {
69 const char *LIBRARY_PATH_SEPARATOR = "/";
70 }
71
72 class PluginLogic::Impl
73 {
74     PluginContainerSupportPtr m_pluginsSupport;
75
76     typedef std::map<JSContextRef, JSPageSessionPtr> PagesSessionsSet;
77     PagesSessionsSet m_sessions;
78     unsigned int m_windowHandle;
79
80   public:
81     Impl();
82     ~Impl();
83
84     // Widget session
85     void initSession(int widgetHandle);
86     void startSession(int widgetHandle,
87                       JSGlobalContextRef context,
88                       double scaleFactor,
89                       const char* encodedBundle,
90                       const char* theme);
91
92     void stopSession(JSGlobalContextRef context);
93
94     void performLibrariesUnload();
95
96     bool loadPluginOnDemand(const WrtDB::DbPluginHandle &pluginHandle,
97                             JavaScriptObject& parentObject,
98                             JSGlobalContextRef context);
99
100     void loadFrame(JSGlobalContextRef context);
101     void unloadFrame(JSGlobalContextRef context);
102
103     void setCustomProperties(JSGlobalContextRef ctx,
104                              double scaleFactor,
105                              const char* encodedBundle,
106                              const char* theme);
107
108     void dispatchJavaScriptEvent(JSGlobalContextRef ctx,
109                                  CustomEventType eventType,
110                                  void* data);
111
112     unsigned int windowHandle() const;
113     void setWindowHandle(unsigned int handle);
114
115     static bool s_sanityCheck;
116 };
117
118 IMPLEMENT_SINGLETON(PluginLogic);
119
120 bool PluginLogic::Impl::s_sanityCheck = false;
121
122 #define PLUGIN_LOGIC_SANITY_CHECK \
123     if (!s_sanityCheck) \
124     { \
125         LogError("Object is not available. Wrong flow occured"); \
126         return; \
127     }
128
129 PluginLogic::Impl::Impl() :
130     m_windowHandle(0)
131 {
132     s_sanityCheck = true;
133
134     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT_PLUGINS");
135     LogDebug("Initializing Plugin Logic...");
136     m_pluginsSupport = PluginContainerSupportPtr(new PluginContainerSupport());
137
138     // explicit call to keep singleton's lifetime until calling destructor.
139     JsFunctionManagerSingleton::Instance();
140     JavaScriptInterfaceSingleton::Instance();
141 }
142
143 PluginLogic::Impl::~Impl()
144 {
145     LogDebug("");
146
147     s_sanityCheck = false;
148
149     FOREACH(it, m_sessions)
150     {
151         LogError("Must stop widget session before exit!");
152         it->second->stopSession();
153     }
154
155     LogDebug("Deinitializing plugin Logic...");
156 }
157
158 void PluginLogic::initSession(int widgetHandle)
159 {
160     m_impl->initSession(widgetHandle);
161 }
162
163 void PluginLogic::startSession(int widgetHandle,
164                                JSGlobalContextRef ctx,
165                                double scaleFactor,
166                                const char* encodedBundle,
167                                const char* theme)
168 {
169     m_impl->startSession(widgetHandle, ctx, scaleFactor, encodedBundle, theme);
170 }
171
172 void PluginLogic::stopSession(JSGlobalContextRef context)
173 {
174     m_impl->stopSession(context);
175 }
176
177 void PluginLogic::performLibrariesUnload()
178 {
179     LogError("Libraries unload TURNED OFF");
180     //    m_impl->performLibrariesUnload();
181 }
182
183 bool PluginLogic::loadPluginOnDemand(
184     const WrtDB::DbPluginHandle &pluginHandle,
185     JavaScriptObject& parentObject,
186     JSGlobalContextRef context)
187 {
188     return m_impl->loadPluginOnDemand(pluginHandle, parentObject, context);
189 }
190
191 void PluginLogic::loadPluginsIntoIframes(JSGlobalContextRef /*context*/)
192 {
193     LogError("This function is Deprecated");
194 }
195
196 void PluginLogic::setCustomProperties(double /*scaleFactor*/,
197                                       const char* /*encodedBundle*/,
198                                       const char* /*theme*/)
199 {
200     LogError("This function is DEPRECATED");
201 }
202
203 void PluginLogic::setCustomProperties(JSGlobalContextRef context,
204                                       double scaleFactor,
205                                       const char* encodedBundle,
206                                       const char* theme)
207 {
208     m_impl->setCustomProperties(context, scaleFactor, encodedBundle, theme);
209 }
210
211 void PluginLogic::dispatchJavaScriptEvent(CustomEventType /*eventType*/)
212 {
213     LogError("This function is DEPRECATED");
214 }
215
216 void PluginLogic::dispatchJavaScriptEvent(JSGlobalContextRef context,
217                                           CustomEventType eventType,
218                                           void *data)
219 {
220     m_impl->dispatchJavaScriptEvent(context, eventType, data);
221 }
222
223 void PluginLogic::loadFrame(JSGlobalContextRef context)
224 {
225     m_impl->loadFrame(context);
226 }
227
228 void PluginLogic::unloadFrame(JSGlobalContextRef context)
229 {
230     m_impl->unloadFrame(context);
231 }
232
233 unsigned int PluginLogic::windowHandle() const
234 {
235     return m_impl->windowHandle();
236 }
237
238 void PluginLogic::setWindowHandle(unsigned int handle)
239 {
240     m_impl->setWindowHandle(handle);
241 }
242
243 PluginLogic::PluginLogic() : m_impl(new PluginLogic::Impl())
244 {}
245
246 PluginLogic::~PluginLogic()
247 {}
248
249 void PluginLogic::Impl::initSession(int widgetHandle)
250 {
251     LogInfo("init pluginLogic...");
252
253     m_pluginsSupport->Initialize(widgetHandle);
254
255     //add standard objects
256     LogDebug("Preload plugins so file");
257
258     PluginContainerSupport::PluginsList pluginList =
259         m_pluginsSupport->getPluginsList();
260
261     FOREACH(it, pluginList)
262     {
263         PluginModelPtr& pluginModel = *it;
264
265         if (!pluginModel->LibraryDependencies.Get()->empty()) {
266             // Only Root Object
267             continue;
268         }
269
270         PluginPtr pluginLib = pluginModel->LibraryInstance.Get();
271
272         if (!pluginLib) {
273             std::string path = pluginModel->LibraryPath.Get() +
274                 std::string(LIBRARY_PATH_SEPARATOR) +
275                 pluginModel->LibraryName.Get();
276
277             pluginLib = Plugin::LoadFromFile(path);
278
279             if (!pluginLib) {
280                 LogError("Loading library failed");
281             } else {
282                 pluginModel->LibraryInstance.Set(pluginLib);
283
284                 LogDebug(
285                     "pluginModel->LibraryInstance.Set() : " <<
286                     pluginLib->GetFileName());
287             }
288         } else {
289             LogDebug("Already loaded");
290         }
291     }
292
293     LogDebug("Preload plugins so file_done");
294 }
295
296 void PluginLogic::Impl::startSession(int widgetHandle,
297                                      JSGlobalContextRef context,
298                                      double scaleFactor,
299                                      const char* encodedBundle,
300                                      const char* theme)
301 {
302     LogInfo("Starting widget session...");
303
304     if (!m_pluginsSupport->isInitialized()) {
305         m_pluginsSupport->Initialize(widgetHandle);
306     }
307     auto sessionIt = m_sessions.find(context);
308
309     // Check if corresponding session if not already created
310     if (sessionIt != m_sessions.end()) {
311         LogWarning("Session already started!");
312         return;
313     }
314
315     auto newSession = JSPageSessionPtr(new JSPageSession(m_pluginsSupport));
316     newSession->startSession(widgetHandle,
317                              context,
318                              scaleFactor,
319                              encodedBundle,
320                              theme);
321
322     m_sessions[context] = newSession;
323 }
324
325 void PluginLogic::Impl::stopSession(JSGlobalContextRef context)
326 {
327     LogInfo("Stopping widget session...");
328
329     auto sessionIt = m_sessions.find(context);
330     if (sessionIt == m_sessions.end()) {
331         LogError("Session not exist!");
332         return;
333     }
334
335     sessionIt->second->stopSession();
336     m_sessions.erase(sessionIt);
337
338     LogInfo("Widget session stopped.");
339 }
340
341 bool PluginLogic::Impl::loadPluginOnDemand(
342     const WrtDB::DbPluginHandle &pluginHandle,
343     JavaScriptObject& parentObject,
344     JSGlobalContextRef context
345     )
346 {
347     LogInfo("Load plugin on demand");
348
349     auto sessionIt = m_sessions.find(context);
350     if (sessionIt == m_sessions.end()) {
351         LogWarning("Session not exist!");
352         return false;
353     }
354
355     return sessionIt->second->loadPluginOnDemand(pluginHandle,
356                                                  parentObject,
357                                                  context);
358 }
359
360 void PluginLogic::Impl::loadFrame(JSGlobalContextRef context)
361 {
362     LogDebug("Load a frame");
363
364     PLUGIN_LOGIC_SANITY_CHECK
365
366     auto sessionIt = m_sessions.find(context);
367     if (sessionIt == m_sessions.end()) {
368         LogWarning("Session not exist!");
369         return;
370     }
371
372     sessionIt->second->loadFrame(context);
373 }
374
375 void PluginLogic::Impl::unloadFrame(JSGlobalContextRef context)
376 {
377     LogDebug("Unload a frame");
378
379     PLUGIN_LOGIC_SANITY_CHECK
380
381     auto sessionIt = m_sessions.find(context);
382     if (sessionIt == m_sessions.end()) {
383         LogWarning("Session not exist!");
384         return;
385     }
386
387     sessionIt->second->unloadFrame(context);
388
389     // I don't know why this session should be removed here.
390     // session list is removed also from stopSession().
391     //m_sessions.erase(sessionIt);
392 }
393
394 void PluginLogic::Impl::setCustomProperties(JSGlobalContextRef context,
395                                             double scaleFactor,
396                                             const char* encodedBundle,
397                                             const char* theme)
398 {
399     LogInfo(
400         "set properties of window object " << scaleFactor << ", "
401                                            << encodedBundle << ", " <<
402         theme);
403
404     PLUGIN_LOGIC_SANITY_CHECK
405
406     auto sessionIt = m_sessions.find(context);
407     if (sessionIt == m_sessions.end()) {
408         LogWarning("Session not exist!");
409         return;
410     }
411
412     sessionIt->second->setCustomProperties(scaleFactor,
413                                            encodedBundle,
414                                            theme);
415 }
416
417 void PluginLogic::Impl::dispatchJavaScriptEvent(JSGlobalContextRef context,
418                                                 CustomEventType eventType,
419                                                 void* data)
420 {
421     LogDebug("Dispatch event");
422
423     PLUGIN_LOGIC_SANITY_CHECK
424
425     auto sessionIt = m_sessions.find(context);
426     if (sessionIt == m_sessions.end()) {
427         LogWarning("Session not exist!");
428         return;
429     }
430
431     sessionIt->second->dispatchJavaScriptEvent(eventType, data);
432 }
433
434 unsigned int PluginLogic::Impl::windowHandle() const
435 {
436     PLUGIN_LOGIC_SANITY_CHECK
437     return m_windowHandle;
438 }
439
440 void PluginLogic::Impl::setWindowHandle(unsigned int handle)
441 {
442     PLUGIN_LOGIC_SANITY_CHECK
443     LogDebug("XWindow handle " << handle);
444     m_windowHandle = handle;
445 }