2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
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)
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
27 #include "plugin_logic.h"
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>
38 #include <JavaScriptCore/JavaScript.h>
41 #include <sys/types.h>
52 #include <wrt_plugin_export.h>
53 #include <js_overlay_types.h>
57 #include "plugin_model.h"
58 #include "javascript_interface.h"
59 #include "js_function_manager.h"
60 #include "plugin_container_support.h"
62 #include "js_page_session.h"
65 using namespace WrtDB;
66 using namespace WrtPlugins::W3C;
69 const char *LIBRARY_PATH_SEPARATOR = "/";
72 class JSPageSession::Impl
75 typedef std::set<PluginPtr> LoadedPlugins;
76 typedef std::set<JSGlobalContextRef> LoadedContexts;
79 ///< Widget handle using this session
82 //view for this session
83 JSGlobalContextRef m_context;
85 bool m_sessionStarted;
87 ///< JS object explorer for this session
88 Explorer* m_objectExplorer;
90 PluginContainerSupportPtr m_pluginsSupport;
92 ///< All loaded plugins. Each one must be unloaded. Plugins means
93 //set of features connected with such plugin (library)
94 LoadedPlugins m_loadedPlugins;
96 // Set of currently loaded web pages' contexts. These contexts are
97 // exactly matching with each frames' global context.
98 LoadedContexts m_loadedContexts;
101 PluginPtr loadLibrary(PluginModelPtr& pluginModel);
103 void loadInjectedJavaScript();
104 void installStandardFeatures();
105 void installRequestedFeatures();
107 //returns true if success or false if failed
108 bool installPlugin(PluginModelPtr plugin);
109 bool installPluginOnDemand(PluginModelPtr plugin,
110 JavaScriptObject& parentObject,
111 JSGlobalContextRef context);
113 void unloadPluginsFromSession();
116 Impl(const PluginContainerSupportPtr& containerSupport);
120 void startSession(int widgetHandle,
121 JSGlobalContextRef view,
123 const char* encodedBundle,
128 void performLibrariesUnload();
130 bool loadPluginOnDemand(const WrtDB::DbPluginHandle &pluginHandle,
131 JavaScriptObject& parentObject,
132 JSGlobalContextRef context);
134 void loadFrame(JSGlobalContextRef context);
135 void unloadFrame(JSGlobalContextRef context);
137 void setCustomProperties(double scaleFactor,
138 const char* encodedBundle,
141 void dispatchJavaScriptEvent(CustomEventType eventType, void* data);
146 JSPageSession::Impl::Impl(const PluginContainerSupportPtr& support) :
147 m_sessionStarted(false)
149 // DPL::Log::LogSystemSingleton::Instance().SetTag("WRT_PLUGINS");
150 LogDebug("Initializing Page Session");
151 m_pluginsSupport = support;
153 // explicit call to keep singleton's lifetime until calling destructor.
154 // JsFunctionManagerSingleton::Instance();
155 // JavaScriptInterfaceSingleton::Instance();
158 JSPageSession::Impl::~Impl()
162 LogError("Must stop widget session before exit!");
166 LogDebug("Deinitializing plugin Logic...");
169 void JSPageSession::Impl::installStandardFeatures()
171 LogInfo("Installing standard widget features...");
173 //add standard functions
174 FOREACH(it, JsFunctionManagerSingleton::Instance().getFunctions())
176 m_objectExplorer->registerObject(*it, NULL);
179 //add standard objects
180 LogDebug("Installing standard extensions...");
182 auto standardPlugins = m_pluginsSupport->getStandardPlugins();
183 FOREACH(it, standardPlugins)
185 //loadFeatureToSession(*it);
189 LogInfo("Standard widget features installed.");
192 bool JSPageSession::Impl::installPlugin(PluginModelPtr plugin)
194 Assert(plugin && "Plugin Model is NULL");
195 auto library = loadLibrary(plugin);
197 LogInfo("Install Plugin '" << library->GetFileName());
202 LogError("Loading library failed");
206 // Register new class
207 FOREACH(it, *(library->GetClassList()))
209 if (!m_objectExplorer->registerObject(*it, NULL)) {
210 LogError("Object Registration failed : " << (*it)->getName());
214 LogDebug("Registered feature.");
218 void JSPageSession::Impl::installRequestedFeatures()
220 LogInfo("Installing requested widget features...");
222 std::list<std::string> allowedFeatures =
223 m_pluginsSupport->getAllowedFeatures(m_widgetHandle);
225 PluginContainerSupport::PluginsList allowedPlugins;
227 FOREACH(feature, allowedFeatures)
229 LogDebug("Processing feature: " << *feature);
231 auto plugin = m_pluginsSupport->getPluginForFeature(*feature);
232 ImplementedObjectsList implObjs =
234 getImplementedObjectsForPluginHandle(plugin->Handle.Get());
236 FOREACH(obj, implObjs)
238 LogDebug("Processing object: " << *obj);
239 /* This can be optimalized, but would need extra data in database.
240 There should be a list of features that are allowed to be
241 installed at widget start */
242 if (obj->find(".") == obj->rfind(".")) {
243 allowedPlugins.push_back(plugin);
244 LogWarning("Plugin will be added: "
245 << plugin->LibraryName.Get());
251 FOREACH(plugin, allowedPlugins)
253 LogDebug("Installation plugin: " << (*plugin)->LibraryName.Get());
254 installPlugin(*plugin);
257 LogInfo("requested features installed.");
260 bool JSPageSession::Impl::loadPluginOnDemand(
261 const WrtDB::DbPluginHandle &pluginHandle,
262 JavaScriptObject& parentObject,
263 JSGlobalContextRef context)
265 LogDebug("load plugin with feature");
267 Assert(parentObject.instance &&
268 !parentObject.name.empty()
269 && "Wrong arguments");
271 if (!m_sessionStarted) {
272 LogError("Session not started");
275 // //TODO here may be a bug. if plugin contains feature rejected and accepted
276 // LogInfo("Installing feature : " << widgetFeature.name);
277 // if (widgetFeature.rejected) {
278 // LogWarning("This api-feature was rejected");
282 auto plugin = m_pluginsSupport->getPluginModelById(pluginHandle);
284 LogError("Failed to load plugin. plugin handle: " << pluginHandle);
288 return installPluginOnDemand(plugin,parentObject,context);
291 bool JSPageSession::Impl::installPluginOnDemand(PluginModelPtr plugin,
292 JavaScriptObject& parentObject,
293 JSGlobalContextRef context)
295 Assert(plugin && "Plugin Model is NULL");
296 auto library = loadLibrary(plugin);
298 LogInfo("Install Plugin '" << library->GetFileName());
302 LogError("Loading library failed");
306 if(!(parentObject.instance))
308 LogError("NULL pointer value");
312 JSObjectPtr parent(new JSObject(parentObject.instance));
314 if (!parent->getObject())
316 LogError("NULL pointer value");
321 FOREACH(it, *(library->GetClassList()))
323 bool installationStatus =
324 m_objectExplorer->registerObject(*it,
329 if(!installationStatus)
331 LogError("Object Registration failed : " << (*it)->getName()
332 << "; Parent object name: " << parentObject.name);
337 LogDebug("Plugin on demand registration completed");
341 void JSPageSession::Impl::setCustomProperties(double scaleFactor,
342 const char* encodedBundle,
345 LogInfo("set properties of window object " << scaleFactor << ", "
346 << encodedBundle << ", " << theme);
348 m_objectExplorer->getWindowPropertySupport()
349 ->setScaleToNavigatorProperty(scaleFactor);
350 m_objectExplorer->getWindowPropertySupport()
351 ->setBundleToWindowProperty(encodedBundle);
352 m_objectExplorer->getWindowPropertySupport()
353 ->setThemeToNavigatorProperty(theme);
356 void JSPageSession::Impl::dispatchJavaScriptEvent(CustomEventType eventType, void* data)
358 // Check if session is already started
359 if (!m_sessionStarted) {
360 LogWarning("Session not started!");
364 LogInfo("Request dispatching javascript event");
365 m_objectExplorer->callEventListeners(eventType, data);
368 void JSPageSession::Impl::loadInjectedJavaScript()
372 std::string DIR_PATH = "/usr/etc/wrt/injected-javascript";
373 std::string JS_EXTENSION = ".js";
375 DIR *dir = opendir(DIR_PATH.c_str());
378 LogError("opendir(\"" << DIR_PATH << "\") error!" );
382 struct dirent* libdir;
383 std::list<std::string> jsFiles;
385 // make file list from DIR_PATH
386 while ((libdir = readdir(dir)) != 0)
388 if (strncmp(libdir->d_name, ".", 2) == 0 ||
389 strncmp(libdir->d_name, "..", 3) == 0)
394 std::string filepath = DIR_PATH;
396 filepath += libdir->d_name;
398 std::string lowercase = filepath;
399 std::transform(lowercase.begin(), lowercase.end(), lowercase.begin(),
402 if( lowercase.rfind(JS_EXTENSION) == std::string::npos ||
403 lowercase.length() !=
404 lowercase.rfind(JS_EXTENSION) + JS_EXTENSION.length() )
406 LogError("This is not js file" << filepath);
412 if (stat(filepath.c_str(), &tmp) == -1) {
413 LogError("Failed to open file " << filepath);
417 if (!S_ISREG(tmp.st_mode)) {
418 LogError("This is not a regular file " << filepath);
422 LogInfo("Added : " << filepath);
423 jsFiles.push_back(filepath);
431 LogDebug("load file : " << (*it));
434 std::ifstream fin(it->c_str());
439 std::getline(fin, line);
440 content += line + "\n";
447 JSValueRef exception = NULL;
449 JSStringCreateWithUTF8CString(content.c_str());
451 JSEvaluateScript(m_context, script, NULL, NULL, 1, &exception);
453 JSStringRelease(script);
457 LogDebug("Exception Occured while injecting javascript "
460 JSStringRef exceptionJSString =
461 JSValueToStringCopy(m_context, exception, NULL);
463 JSStringGetMaximumUTF8CStringSize(exceptionJSString);
464 char* exceptionString = new char[size];
465 JSStringGetUTF8CString(exceptionJSString,
466 exceptionString, size);
467 LogDebug("Exception : " << exceptionString);
469 delete [] exceptionString;
470 JSStringRelease(exceptionJSString);
476 void JSPageSession::Impl::startSession(int widgetHandle,
477 JSGlobalContextRef context,
479 const char* encodedBundle,
482 LogInfo("Starting widget session...");
484 // Check if corresponding session if not already created
485 if (m_sessionStarted) {
486 LogWarning("Session already started!");
490 // Create js object explorer object
491 m_objectExplorer = new Explorer(context);
493 m_sessionStarted = true;
494 m_widgetHandle = widgetHandle;
495 m_loadedPlugins.clear();
498 // Register standard features
499 installStandardFeatures();
501 // Register special features
502 installRequestedFeatures();
504 // set scale, bundle as window's property
505 setCustomProperties(scaleFactor, encodedBundle, theme);
507 // Load injected javascript files
508 loadInjectedJavaScript();
509 LogInfo("Widget session started.");
512 void JSPageSession::Impl::stopSession()
514 LogInfo("Stopping widget session...");
516 if (!m_sessionStarted) {
517 LogWarning("Session not started!");
521 unloadPluginsFromSession();
522 m_sessionStarted = false;
524 LogInfo("Widget session stopped.");
528 void JSPageSession::Impl::unloadPluginsFromSession()
530 LogDebug("Unload plugins from session");
532 m_objectExplorer->removePluginsFromIframes();
533 m_objectExplorer->cleanIframesData();
535 // delete js object for overlayed js functions
536 FOREACH(it, JsFunctionManagerSingleton::Instance().getFunctions())
538 m_objectExplorer->deregisterObject(*it);
541 // delete js object for plugins
542 FOREACH(pluginIt, m_loadedPlugins)
544 LogDebug("Unregistering plugin " << (*pluginIt)->GetFileName());
546 (*pluginIt)->OnWidgetStop(m_widgetHandle);
547 LogDebug("Emitted WidgetStop for plugin: " <<
548 (*pluginIt)->GetFileName());
550 FOREACH(it, *((*pluginIt)->GetClassList()))
552 m_objectExplorer->deregisterObject(*it);
556 JavaScriptInterfaceSingleton::Instance().invokeGarbageCollector(m_context);
558 m_loadedPlugins.clear();
560 delete m_objectExplorer;
561 m_objectExplorer = NULL;
567 void JSPageSession::Impl::performLibrariesUnload()
570 LogDebug("Perform library unload");
572 size_t unloadedLibraries = 0;
574 FOREACH(pluginIt, m_loadedPlugins)
576 LogDebug("Preparing library: " << (*pluginIt)->LibraryName.Get());
578 PluginPtr plugin = (*pluginIt)->LibraryInstance.Get();
580 LogWarning("Library not loaded " << (*pluginIt)->LibraryName.Get());
584 (*pluginIt)->LibraryInstance.Set(PluginPtr());
587 LogInfo("unloaded " << unloadedLibraries << " unreferenced libraries!");
591 PluginPtr JSPageSession::Impl::loadLibrary(PluginModelPtr& pluginModel)
593 PluginPtr pluginLib = pluginModel->LibraryInstance.Get();
596 std::string path = pluginModel->LibraryPath.Get() +
597 std::string(LIBRARY_PATH_SEPARATOR) +
598 pluginModel->LibraryName.Get();
600 pluginLib = Plugin::LoadFromFile(path);
604 LogError("Loading library failed");
607 pluginModel->LibraryInstance.Set(pluginLib);
609 LogDebug("On widget start");
610 // This is first time for this plugin, start widget Session
611 pluginLib->OnWidgetStart(
613 m_loadedPlugins.insert(pluginLib);
615 FOREACH(context, m_loadedContexts)
617 pluginLib->OnFrameLoad(*context);
623 LogDebug("Get from LibraryInstance");
624 LogDebug("On widget start");
625 // This is first time for this plugin, start widget Session
626 pluginLib->OnWidgetStart(
628 m_loadedPlugins.insert(pluginLib);
630 FOREACH(context, m_loadedContexts)
632 pluginLib->OnFrameLoad(*context);
640 void JSPageSession::Impl::loadFrame(JSGlobalContextRef context)
642 LogDebug("Load a frame");
644 if (!m_sessionStarted) {
645 LogWarning("Session NOT started!");
649 m_loadedContexts.insert(context);
651 FOREACH(pluginIt, m_loadedPlugins)
653 LogDebug("load plugin to frame" << (*pluginIt)->GetFileName());
655 (*pluginIt)->OnFrameLoad(context);
658 m_objectExplorer->loadFrame(context);
661 void JSPageSession::Impl::unloadFrame(JSGlobalContextRef context)
663 LogDebug("Unload a frame");
665 if (!m_sessionStarted) {
666 LogWarning("Session NOT started!");
670 m_loadedContexts.erase(context);
672 FOREACH(pluginIt, m_loadedPlugins)
674 LogDebug("unload plugin to frame" << (*pluginIt)->GetFileName());
676 (*pluginIt)->OnFrameUnload(context);
679 m_objectExplorer->unloadFrame(context);
683 void JSPageSession::startSession(int widgetHandle,
684 JSGlobalContextRef ctx,
686 const char* encodedBundle,
689 m_impl->startSession(widgetHandle, ctx, scaleFactor, encodedBundle, theme);
692 void JSPageSession::stopSession()
694 m_impl->stopSession();
697 void JSPageSession::performLibrariesUnload()
699 m_impl->performLibrariesUnload();
702 bool JSPageSession::loadPluginOnDemand(
703 const WrtDB::DbPluginHandle &pluginHandle,
704 JavaScriptObject& parentObject,
705 JSGlobalContextRef context)
707 return m_impl->loadPluginOnDemand(pluginHandle, parentObject, context);
710 void JSPageSession::setCustomProperties(double scaleFactor,
711 const char* encodedBundle,
714 m_impl->setCustomProperties(scaleFactor, encodedBundle, theme);
717 void JSPageSession::dispatchJavaScriptEvent(CustomEventType eventType, void* data)
719 m_impl->dispatchJavaScriptEvent(eventType, data);
722 void JSPageSession::loadFrame(JSGlobalContextRef context)
724 m_impl->loadFrame(context);
727 void JSPageSession::unloadFrame(JSGlobalContextRef context)
729 m_impl->unloadFrame(context);
732 JSPageSession::JSPageSession(const PluginContainerSupportPtr& containerSupport)
733 : m_impl(new JSPageSession::Impl(containerSupport))
737 JSPageSession::~JSPageSession()