[Release] wrt-plugins-common_0.3.94
[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 rootPluginList =
259         m_pluginsSupport->getRootPlugins();
260
261     FOREACH(it, rootPluginList)
262     {
263         PluginModelPtr& pluginModel = *it;
264         PluginPtr pluginLib = pluginModel->LibraryInstance.Get();
265
266         if (!pluginLib) {
267             std::string path = pluginModel->LibraryPath.Get() +
268                 std::string(LIBRARY_PATH_SEPARATOR) +
269                 pluginModel->LibraryName.Get();
270
271             pluginLib = Plugin::LoadFromFile(path);
272
273             if (!pluginLib) {
274                 LogError("Loading library failed");
275             } else {
276                 pluginModel->LibraryInstance.Set(pluginLib);
277
278                 LogDebug(
279                     "pluginModel->LibraryInstance.Set() : " <<
280                     pluginLib->GetFileName());
281             }
282         } else {
283             LogDebug("Already loaded");
284         }
285     }
286
287     LogDebug("Preload plugins so file_done");
288 }
289
290 void PluginLogic::Impl::startSession(int widgetHandle,
291                                      JSGlobalContextRef context,
292                                      double scaleFactor,
293                                      const char* encodedBundle,
294                                      const char* theme)
295 {
296     LogInfo("Starting widget session...");
297
298     if (!m_pluginsSupport->isInitialized()) {
299         m_pluginsSupport->Initialize(widgetHandle);
300     }
301     auto sessionIt = m_sessions.find(context);
302
303     // Check if corresponding session if not already created
304     if (sessionIt != m_sessions.end()) {
305         LogWarning("Session already started!");
306         return;
307     }
308
309     auto newSession = JSPageSessionPtr(new JSPageSession(m_pluginsSupport));
310     newSession->startSession(widgetHandle,
311                              context,
312                              scaleFactor,
313                              encodedBundle,
314                              theme);
315
316     m_sessions[context] = newSession;
317 }
318
319 void PluginLogic::Impl::stopSession(JSGlobalContextRef context)
320 {
321     LogInfo("Stopping widget session...");
322
323     auto sessionIt = m_sessions.find(context);
324     if (sessionIt == m_sessions.end()) {
325         LogError("Session not exist!");
326         return;
327     }
328
329     sessionIt->second->stopSession();
330     m_sessions.erase(sessionIt);
331
332     LogInfo("Widget session stopped.");
333 }
334
335 bool PluginLogic::Impl::loadPluginOnDemand(
336     const WrtDB::DbPluginHandle &pluginHandle,
337     JavaScriptObject& parentObject,
338     JSGlobalContextRef context
339     )
340 {
341     LogInfo("Load plugin on demand");
342
343     auto sessionIt = m_sessions.find(context);
344     if (sessionIt == m_sessions.end()) {
345         LogWarning("Session not exist!");
346         return false;
347     }
348
349     return sessionIt->second->loadPluginOnDemand(pluginHandle,
350                                                  parentObject,
351                                                  context);
352 }
353
354 void PluginLogic::Impl::loadFrame(JSGlobalContextRef context)
355 {
356     LogDebug("Load a frame");
357
358     PLUGIN_LOGIC_SANITY_CHECK
359
360     auto sessionIt = m_sessions.find(context);
361     if (sessionIt == m_sessions.end()) {
362         LogWarning("Session not exist!");
363         return;
364     }
365
366     sessionIt->second->loadFrame(context);
367 }
368
369 void PluginLogic::Impl::unloadFrame(JSGlobalContextRef context)
370 {
371     LogDebug("Unload a frame");
372
373     PLUGIN_LOGIC_SANITY_CHECK
374
375     auto sessionIt = m_sessions.find(context);
376     if (sessionIt == m_sessions.end()) {
377         LogWarning("Session not exist!");
378         return;
379     }
380
381     sessionIt->second->unloadFrame(context);
382
383     // I don't know why this session should be removed here.
384     // session list is removed also from stopSession().
385     //m_sessions.erase(sessionIt);
386 }
387
388 void PluginLogic::Impl::setCustomProperties(JSGlobalContextRef context,
389                                             double scaleFactor,
390                                             const char* encodedBundle,
391                                             const char* theme)
392 {
393     LogInfo(
394         "set properties of window object " << scaleFactor << ", "
395                                            << encodedBundle << ", " <<
396         theme);
397
398     PLUGIN_LOGIC_SANITY_CHECK
399
400     auto sessionIt = m_sessions.find(context);
401     if (sessionIt == m_sessions.end()) {
402         LogWarning("Session not exist!");
403         return;
404     }
405
406     sessionIt->second->setCustomProperties(scaleFactor,
407                                            encodedBundle,
408                                            theme);
409 }
410
411 void PluginLogic::Impl::dispatchJavaScriptEvent(JSGlobalContextRef context,
412                                                 CustomEventType eventType,
413                                                 void* data)
414 {
415     LogDebug("Dispatch event");
416
417     PLUGIN_LOGIC_SANITY_CHECK
418
419     auto sessionIt = m_sessions.find(context);
420     if (sessionIt == m_sessions.end()) {
421         LogWarning("Session not exist!");
422         return;
423     }
424
425     sessionIt->second->dispatchJavaScriptEvent(eventType, data);
426 }
427
428 unsigned int PluginLogic::Impl::windowHandle() const
429 {
430     if (!s_sanityCheck)
431     {
432         LogError("Object is not available. Wrong flow occured");
433     }
434     return m_windowHandle;
435 }
436
437 void PluginLogic::Impl::setWindowHandle(unsigned int handle)
438 {
439     PLUGIN_LOGIC_SANITY_CHECK
440     LogDebug("XWindow handle " << handle);
441     m_windowHandle = handle;
442 }