merge with master
[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
79   public:
80     Impl();
81     ~Impl();
82
83     // Widget session
84     void initSession(int widgetHandle);
85     void startSession(int widgetHandle,
86                       JSGlobalContextRef context,
87                       double scaleFactor,
88                       const char* encodedBundle,
89                       const char* theme);
90
91     void stopSession(JSGlobalContextRef context);
92
93     void performLibrariesUnload();
94
95     bool loadPluginOnDemand(const WrtDB::DbPluginHandle &pluginHandle,
96                             JavaScriptObject& parentObject,
97                             JSGlobalContextRef context);
98
99     void loadFrame(JSGlobalContextRef context);
100     void unloadFrame(JSGlobalContextRef context);
101
102     void setCustomProperties(JSGlobalContextRef ctx,
103                              double scaleFactor,
104                              const char* encodedBundle,
105                              const char* theme);
106
107     void dispatchJavaScriptEvent(JSGlobalContextRef ctx,
108                                  CustomEventType eventType,
109                                  void* data);
110
111     static bool s_sanityCheck;
112 };
113
114 IMPLEMENT_SINGLETON(PluginLogic);
115
116 bool PluginLogic::Impl::s_sanityCheck = false;
117
118 #define PLUGIN_LOGIC_SANITY_CHECK \
119     if (!s_sanityCheck) \
120     { \
121         LogError("Object is not available. Wrong flow occured"); \
122         return; \
123     }
124
125 PluginLogic::Impl::Impl()
126 {
127     s_sanityCheck = true;
128
129     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT_PLUGINS");
130     LogDebug("Initializing Plugin Logic...");
131     m_pluginsSupport = PluginContainerSupportPtr(new PluginContainerSupport());
132
133     // explicit call to keep singleton's lifetime until calling destructor.
134     JsFunctionManagerSingleton::Instance();
135     JavaScriptInterfaceSingleton::Instance();
136 }
137
138 PluginLogic::Impl::~Impl()
139 {
140     LogDebug("");
141
142     s_sanityCheck = false;
143
144     FOREACH(it, m_sessions)
145     {
146         LogError("Must stop widget session before exit!");
147         it->second->stopSession();
148     }
149
150     LogDebug("Deinitializing plugin Logic...");
151 }
152
153 void PluginLogic::initSession(int widgetHandle)
154 {
155     m_impl->initSession(widgetHandle);
156 }
157
158 void PluginLogic::startSession(int widgetHandle,
159                                JSGlobalContextRef ctx,
160                                double scaleFactor,
161                                const char* encodedBundle,
162                                const char* theme)
163 {
164     m_impl->startSession(widgetHandle, ctx, scaleFactor, encodedBundle, theme);
165 }
166
167 void PluginLogic::stopSession(JSGlobalContextRef context)
168 {
169     m_impl->stopSession(context);
170 }
171
172 void PluginLogic::performLibrariesUnload()
173 {
174     LogError("Libraries unload TURNED OFF");
175     //    m_impl->performLibrariesUnload();
176 }
177
178 bool PluginLogic::loadPluginOnDemand(
179     const WrtDB::DbPluginHandle &pluginHandle,
180     JavaScriptObject& parentObject,
181     JSGlobalContextRef context)
182 {
183     return m_impl->loadPluginOnDemand(pluginHandle, parentObject, context);
184 }
185
186 void PluginLogic::loadPluginsIntoIframes(JSGlobalContextRef /*context*/)
187 {
188     LogError("This function is Deprecated");
189 }
190
191 void PluginLogic::setCustomProperties(double /*scaleFactor*/,
192                                       const char* /*encodedBundle*/,
193                                       const char* /*theme*/)
194 {
195     LogError("This function is DEPRECATED");
196 }
197
198 void PluginLogic::setCustomProperties(JSGlobalContextRef context,
199                                       double scaleFactor,
200                                       const char* encodedBundle,
201                                       const char* theme)
202 {
203     m_impl->setCustomProperties(context, scaleFactor, encodedBundle, theme);
204 }
205
206 void PluginLogic::dispatchJavaScriptEvent(CustomEventType /*eventType*/)
207 {
208     LogError("This function is DEPRECATED");
209 }
210
211 void PluginLogic::dispatchJavaScriptEvent(JSGlobalContextRef context,
212                                           CustomEventType eventType,
213                                           void *data)
214 {
215     m_impl->dispatchJavaScriptEvent(context, eventType, data);
216 }
217
218 void PluginLogic::loadFrame(JSGlobalContextRef context)
219 {
220     m_impl->loadFrame(context);
221 }
222
223 void PluginLogic::unloadFrame(JSGlobalContextRef context)
224 {
225     m_impl->unloadFrame(context);
226 }
227
228 PluginLogic::PluginLogic() : m_impl(new PluginLogic::Impl())
229 {}
230
231 PluginLogic::~PluginLogic()
232 {}
233
234 void PluginLogic::Impl::initSession(int widgetHandle)
235 {
236     LogInfo("init pluginLogic...");
237
238     m_pluginsSupport->Initialize(widgetHandle);
239
240     //add standard objects
241     LogDebug("Preload plugins so file");
242
243     PluginContainerSupport::PluginsList pluginList =
244         m_pluginsSupport->getPluginsList();
245
246     FOREACH(it, pluginList)
247     {
248         PluginModelPtr& pluginModel = *it;
249
250         if (!pluginModel->LibraryDependencies.Get()->empty()) {
251             // Only Root Object
252             continue;
253         }
254
255         PluginPtr pluginLib = pluginModel->LibraryInstance.Get();
256
257         if (!pluginLib) {
258             std::string path = pluginModel->LibraryPath.Get() +
259                 std::string(LIBRARY_PATH_SEPARATOR) +
260                 pluginModel->LibraryName.Get();
261
262             pluginLib = Plugin::LoadFromFile(path);
263
264             if (!pluginLib) {
265                 LogError("Loading library failed");
266             } else {
267                 pluginModel->LibraryInstance.Set(pluginLib);
268
269                 LogDebug(
270                     "pluginModel->LibraryInstance.Set() : " <<
271                     pluginLib->GetFileName());
272             }
273         } else {
274             LogDebug("Already loaded");
275         }
276     }
277
278     LogDebug("Preload plugins so file_done");
279 }
280
281 void PluginLogic::Impl::startSession(int widgetHandle,
282                                      JSGlobalContextRef context,
283                                      double scaleFactor,
284                                      const char* encodedBundle,
285                                      const char* theme)
286 {
287     LogInfo("Starting widget session...");
288
289     if (!m_pluginsSupport->isInitialized()) {
290         m_pluginsSupport->Initialize(widgetHandle);
291     }
292     auto sessionIt = m_sessions.find(context);
293
294     // Check if corresponding session if not already created
295     if (sessionIt != m_sessions.end()) {
296         LogWarning("Session already started!");
297         return;
298     }
299
300     auto newSession = JSPageSessionPtr(new JSPageSession(m_pluginsSupport));
301     newSession->startSession(widgetHandle,
302                              context,
303                              scaleFactor,
304                              encodedBundle,
305                              theme);
306
307     m_sessions[context] = newSession;
308 }
309
310 void PluginLogic::Impl::stopSession(JSGlobalContextRef context)
311 {
312     LogInfo("Stopping widget session...");
313
314     auto sessionIt = m_sessions.find(context);
315     if (sessionIt == m_sessions.end()) {
316         LogError("Session not exist!");
317         return;
318     }
319
320     sessionIt->second->stopSession();
321     m_sessions.erase(sessionIt);
322
323     LogInfo("Widget session stopped.");
324 }
325
326 bool PluginLogic::Impl::loadPluginOnDemand(
327     const WrtDB::DbPluginHandle &pluginHandle,
328     JavaScriptObject& parentObject,
329     JSGlobalContextRef context
330     )
331 {
332     LogInfo("Load plugin on demand");
333
334     auto sessionIt = m_sessions.find(context);
335     if (sessionIt == m_sessions.end()) {
336         LogWarning("Session not exist!");
337         return false;
338     }
339
340     return sessionIt->second->loadPluginOnDemand(pluginHandle,
341                                                  parentObject,
342                                                  context);
343 }
344
345 void PluginLogic::Impl::loadFrame(JSGlobalContextRef context)
346 {
347     LogDebug("Load a frame");
348
349     PLUGIN_LOGIC_SANITY_CHECK
350
351     auto sessionIt = m_sessions.find(context);
352     if (sessionIt == m_sessions.end()) {
353         LogWarning("Session not exist!");
354         return;
355     }
356
357     sessionIt->second->loadFrame(context);
358 }
359
360 void PluginLogic::Impl::unloadFrame(JSGlobalContextRef context)
361 {
362     LogDebug("Unload 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->unloadFrame(context);
373
374     // I don't know why this session should be removed here.
375     // session list is removed also from stopSession().
376     //m_sessions.erase(sessionIt);
377 }
378
379 void PluginLogic::Impl::setCustomProperties(JSGlobalContextRef context,
380                                             double scaleFactor,
381                                             const char* encodedBundle,
382                                             const char* theme)
383 {
384     LogInfo(
385         "set properties of window object " << scaleFactor << ", "
386                                            << encodedBundle << ", " <<
387         theme);
388
389     PLUGIN_LOGIC_SANITY_CHECK
390
391     auto sessionIt = m_sessions.find(context);
392     if (sessionIt == m_sessions.end()) {
393         LogWarning("Session not exist!");
394         return;
395     }
396
397     sessionIt->second->setCustomProperties(scaleFactor,
398                                            encodedBundle,
399                                            theme);
400 }
401
402 void PluginLogic::Impl::dispatchJavaScriptEvent(JSGlobalContextRef context,
403                                                 CustomEventType eventType,
404                                                 void* data)
405 {
406     LogDebug("Dispatch event");
407
408     PLUGIN_LOGIC_SANITY_CHECK
409
410     auto sessionIt = m_sessions.find(context);
411     if (sessionIt == m_sessions.end()) {
412         LogWarning("Session not exist!");
413         return;
414     }
415
416     sessionIt->second->dispatchJavaScriptEvent(eventType, data);
417 }