PluginEngine.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file PluginEngine.cpp
22 
23  \brief A plugin engine for plugins written in JavaScript using Google's V8 engine.
24  */
25 
26 // TerraLib
27 #include "../../../common/Exception.h"
28 #include "../../../core/logger/Logger.h"
29 #include "../../../core/translator/Translator.h"
30 #include "../common/JsContext.h"
31 #include "../common/JsContextManager.h"
32 #include "../common/Utils.h"
33 #include "../jsi/platform/OpenModules.h"
34 #include "Plugin.h"
35 #include "PluginEngine.h"
36 
37 // STL
38 #include <algorithm>
39 #include <cassert>
40 #include <functional>
41 #include <memory>
42 
43 // Boost
44 #include <boost/filesystem.hpp>
45 
46 // Google V8
47 #include <v8.h>
48 
50 {
51 // let's create the JavaScript plugin and then find out all information needed to execute it
52  std::auto_ptr<Plugin> jsplugin(new Plugin(pInfo));
53 
54 // find the context to use for plugin
55  std::vector<te::plugin::PluginInfo::Parameter>::const_iterator itP = std::find_if(pInfo.m_parameters.begin(),
56  pInfo.m_parameters.end(),
57  te::plugin::PluginInfo::Finder1st("CONTEXT_ID"));
58 
59  std::string ctxid = "DEFAULT";
60 
61  if(itP != pInfo.m_parameters.end())
62  ctxid = itP->second;
63 
65 
66  if(ctx == 0)
67  {
68 // create the new context
69  std::auto_ptr<te::v8::common::JsContext> jsctx(new te::v8::common::JsContext);
70  te::v8::common::JsContextManager::getInstance().add(ctxid, jsctx.get());
71  ctx = jsctx.release();
72 
73 // and then register the C++ code for JavaScript users!
74  ::v8::Persistent<::v8::Context> context = ctx->getCtx();
75  ::v8::Context::Scope contextScope(context);
76  ::v8::HandleScope handleScope;
77  ::v8::Local<::v8::FunctionTemplate> jsPrintFunction = ::v8::FunctionTemplate::New(te::v8::common::Print);
78  context->Global()->Set(::v8::String::New("print"), jsPrintFunction->GetFunction());
79  te::v8::jsi::RegisterModule(context->Global());
80  }
81 
82  jsplugin->m_ctx = ctx;
83 
84 // let's create the required V8 environment in order to run plugin's code
85  ::v8::Persistent<::v8::Context> context = ctx->getCtx();
86  ::v8::Context::Scope contextScope(context);
87  ::v8::HandleScope handleScope;
88 
89 // the plugin file name must have the path with its relative directory from the application execution path
90  std::vector<te::plugin::PluginInfo::Resource>::const_iterator itR = std::find_if(pInfo.m_resources.begin(),
91  pInfo.m_resources.end(),
92  te::plugin::PluginInfo::Finder1st("PluginFileName"));
93 
94  if(itR == pInfo.m_resources.end())
95  throw te::common::Exception(TR_V8PLUGIN("Could not find JavaScript plugin file!"));
96 
97  boost::filesystem::path pluginFile(pInfo.m_folder);
98  pluginFile /= itR->second;
99 
100  ::v8::Handle<::v8::String> source = te::v8::common::ReadFile(pluginFile.file_string());
101 
102  ::v8::Handle<::v8::Script> script = ::v8::Script::Compile(source);
103 
104  ::v8::TryCatch trycatch;
105 
106  ::v8::Handle<::v8::Value> result = script->Run();
107 
108  if(result.IsEmpty())
109  {
110  ::v8::Handle<::v8::Value> e = trycatch.Exception();
111  ::v8::String::AsciiValue estr(e);
112  throw te::common::Exception(*estr);
113  }
114 
115 // find plugin class name in plugin parameter info
116  itP = std::find_if(pInfo.m_parameters.begin(),
117  pInfo.m_parameters.end(),
118  te::plugin::PluginInfo::Finder1st("PLUGIN_CLASS_NAME"));
119 
120  if(itP == pInfo.m_parameters.end())
121  return jsplugin.release(); // ok: the user doesn't want to execute nothing... just go away!
122 
123  const std::string& pluginClassName = itP->second;
124 
125 // find plugin class in global context and caches its constructor
126  ::v8::Local<::v8::String> jsPluginClassName = ::v8::String::New(pluginClassName.c_str());
127  ::v8::Local<::v8::Value> jsPluginClass = context->Global()->Get(jsPluginClassName);
128 
129  if(jsPluginClass.IsEmpty())
130  throw te::common::Exception(TR_V8PLUGIN("Could not find Plugin's constructor using the informed JavaScript code!"));
131 
132  if(!jsPluginClass->IsFunction())
133  throw te::common::Exception(TR_V8PLUGIN("Plugin's constructor must be a function!"));
134 
135  ::v8::Handle<::v8::Function> jsPluginClassFtor = ::v8::Handle<::v8::Function>::Cast(jsPluginClass);
136  jsplugin->m_jspluginFtor = ::v8::Persistent<::v8::Function>::New(jsPluginClassFtor);
137 
138 // then caches an instance of the plugin
139  ::v8::Local<::v8::Object> jsPlugin = jsPluginClassFtor->NewInstance();
140 
141  if(jsPlugin.IsEmpty())
142  throw te::common::Exception(TR_V8PLUGIN("Could not create a plugin using the informed JavaScript code!"));
143 
144  jsplugin->m_jsplugin = ::v8::Persistent<::v8::Object>::New(jsPlugin);
145 
146 // cache plugin's startup method
147  te::v8::common::Cache(jsPlugin, "startup", jsplugin->m_startup);
148 
149 // cache plugin's shutdown method
150  te::v8::common::Cache(jsPlugin, "shutdown", jsplugin->m_shutdown);
151 
152  return jsplugin.release();
153 }
154 
156 {
157  assert(plugin && plugin->getInfo().m_engine == TE_V8_PLUGIN_ENGINE_CODE);
158 
159  delete plugin;
160 }
161 
#define TE_V8_PLUGIN_ENGINE_CODE
The plugin engine name for Java plugins.
An abstract class for TerraLib Plugins.
TEV8COMMONEXPORT::v8::Handle<::v8::String > ReadFile(const std::string &fileName)
It reads a file into a v8 string.
A class for keeping reference to a persistent context.
Definition: JsContext.h:54
TEV8JSIEXPORT void RegisterModule(::v8::Local<::v8::Object > &global)
It register the Module class.
Definition: OpenModules.cpp:31
#define TR_V8PLUGIN(message)
It marks a string in order to get translated. This is a special mark used in the Vector Geometry modu...
static JsContextManager & getInstance()
It returns a reference to the singleton instance.
TEV8COMMONEXPORT void Cache(::v8::Local<::v8::Object > &obj, const std::string &methodName,::v8::Persistent<::v8::Function > &outFtor)
It caches the object method into the persistent output functor.
This class is designed to declare objects to be thrown as exceptions by TerraLib. ...
void unload(te::plugin::AbstractPlugin *plugin)
It try to unload the informed plugin.
A plugin engine for plugins written in JavaScript using Google&#39;s V8 engine.
The basic information about a plugin.
TEV8COMMONEXPORT::v8::Handle<::v8::Value > Print(const ::v8::Arguments &args)
This function will print all the arguments to the standard output.
A class that handles JavaScript Plugins using Google&#39;s V8 engine.
te::plugin::AbstractPlugin * load(const te::plugin::PluginInfo &pInfo)
It try to create and load the informed plugin.