src/terralib/core/plugin/CppPluginEngine.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
3 
4  This file is part of the TerraLib - a Framework for building GIS enabled applications.
5 
6  TerraLib is free software: you can redistribute it and/or modify
7  it under the terms of the GNU Lesser General Public License as published by
8  the Free Software Foundation, either version 3 of the License,
9  or (at your option) any later version.
10 
11  TerraLib is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public License
17  along with TerraLib. See COPYING. If not, write to
18  TerraLib Team at <terralib-team@terralib.org>.
19  */
20 
21 /*!
22  \file terralib/core/plugin/CppPluginEngine.cpp
23 
24  \brief A plugin engine for plugins written in C++.
25 
26  \author Gilberto Ribeiro de Queiroz
27  \author Matheus Cavassan Zaglia
28  */
29 
30 // TerraLib
31 #include "CppPluginEngine.h"
32 #include "../filesystem/FileSystem.h"
33 #include "../lib/Library.h"
34 #include "../logger/Logger.h"
35 #include "../translator/Translator.h"
36 #include "CppPlugin.h"
37 #include "CppPluginProxy.h"
38 #include "Exception.h"
39 
40 // STL
41 #include <algorithm>
42 #include <cassert>
43 
44 // Boost
45 #include <boost/filesystem.hpp>
46 #include <boost/format.hpp>
47 
49 {
50  std::string engine_id;
51  std::string engine_name;
52 };
53 
55  : m_pimpl(nullptr)
56 {
57  m_pimpl = new Impl;
58  m_pimpl->engine_id = "C++";
59  m_pimpl->engine_name = "Engine for plugins written in C++";
60 }
61 
63 {
64  delete m_pimpl;
65 }
66 
67 const std::string&
69 {
70  return m_pimpl->engine_id;
71 }
72 
73 const std::string&
75 {
76  return m_pimpl->engine_name;
77 }
78 
79 std::unique_ptr<te::core::AbstractPlugin>
81 {
82 // get the plugin's shared library name in the resources list
83  std::vector<Resource>::const_iterator it = std::find_if(pinfo.resources.begin(),
84  pinfo.resources.end(),
85  []
86  (const Resource& r)
87  {
88  return r.first == "shared_library_name";
89  });
90 
91  if(it == pinfo.resources.end())
92  {
93  boost::format err_msg(TE_TR("Shared library name not informed for plugin: %1%."));
94 
95  throw PluginEngineLoadException() << ErrorDescription((err_msg % pinfo.name).str());
96  }
97 
98 // get the adequate name depending on the platform and build type
99  std::string slib_name = Library::getNativeName(it->second);
100 
101  boost::filesystem::path plugin_file(slib_name);
102 
103  std::shared_ptr<Library> slib(new Library(plugin_file.string(), true));
104 
105  std::string err_msg;
106 
107  boost::format loading_log_msg(TE_TR("Trying to load plugin '%1%' as: %2%"));
108  boost::format err_log_msg(TE_TR("Plugin '%1%' could not loaded as: %2%"));
109  boost::filesystem::path path(te::core::FileSystem::currentPath());
110  try
111  {
112  TE_LOG_TRACE(
113  (loading_log_msg % pinfo.name %
114  te::core::FileSystem::absolutePath((path / plugin_file).string()))
115  .str());
116  slib->load();
117  }
118  catch(const te::core::Exception&)
119  {
120  err_msg += plugin_file.string();
121  TE_LOG_TRACE(
122  (err_log_msg % pinfo.name % te::core::FileSystem::absolutePath(
123  (path / plugin_file).string())).str());
124  }
125 #if(TE_PLATFORM == TE_PLATFORMCODE_APPLE)
126  if(!slib->isLoaded())
127  {
128  try
129  {
130  plugin_file = "./";
131  plugin_file /= slib_name;
132  slib.reset(new te::core::Library(plugin_file.string(), true));
133  TE_LOG_TRACE(
134  (loading_log_msg % pinfo.name %
135  te::core::FileSystem::absolutePath((path / plugin_file).string()))
136  .str());
137  slib->load();
138  err_msg.clear();
139  }
140  catch(te::core::Exception& e)
141  {
142  err_msg += '\n';
143  err_msg += plugin_file.string();
144  TE_LOG_TRACE(
145  (err_log_msg % pinfo.name %
146  te::core::FileSystem::absolutePath((path / plugin_file).string()))
147  .str());
148  }
149 
150  if(!slib->isLoaded())
151  {
152  try
153  {
154  plugin_file = "./";
155  plugin_file /= "lib";
156  plugin_file /= slib_name;
157  slib.reset(new te::core::Library(plugin_file.string(), true));
158  TE_LOG_TRACE(
159  (loading_log_msg % pinfo.name %
160  te::core::FileSystem::absolutePath((path / plugin_file).string()))
161  .str());
162  slib->load();
163  err_msg.clear();
164  }
165  catch(te::core::Exception& exc)
166  {
167  err_msg += '\n';
168  err_msg += plugin_file.string();
169  TE_LOG_TRACE(
170  (err_log_msg % pinfo.name %
171  te::core::FileSystem::absolutePath((path / plugin_file).string()))
172  .str());
173  }
174  }
175  }
176 #endif
177  if(!slib->isLoaded())
178  {
179  boost::format err(TE_TR("Could not find shared library as:\n%1%"));
180 
181  throw PluginLoadException() << ErrorDescription((err % err_msg).str());
182  }
183 
184 
185 // now we need to get the plugin constructor function address
186  void* fptr = slib->getAddress("te_cpp_plugin_get_instance");
187 
188  te_get_plugin_fnct_t plugin_entry = reinterpret_cast<te_get_plugin_fnct_t>(fptr);
189 
190  if(plugin_entry == nullptr)
191  {
192  boost::format err_msg(TE_TR("Could not find entry point '%1%' for plugin '%2%'."));
193  TE_LOG_TRACE((err_msg % "te_cpp_plugin_get_instance" % pinfo.name).str());
194  throw PluginEngineLoadException() << ErrorDescription((err_msg % "te_cpp_plugin_get_instance" % pinfo.name).str());
195  }
196 
197  std::unique_ptr<CppPlugin> cpp_plugin(plugin_entry(pinfo));
198 
199  if(cpp_plugin == nullptr)
200  {
201  boost::format err_msg(TE_TR("Plugin '%1%' returned a null entry."));
202  TE_LOG_TRACE((err_msg % pinfo.name).str());
203  throw PluginEngineLoadException() << ErrorDescription((err_msg % pinfo.name).str());
204  }
205 
206  std::unique_ptr<CppPluginProxy> proxy(new CppPluginProxy(slib, std::move(cpp_plugin)));
207 
208  return std::move(proxy);
209 }
210 
211 void
212 te::core::CppPluginEngine::unload(std::unique_ptr<AbstractPlugin> plugin)
213 {
214  if(plugin == nullptr)
215  return;
216 
217  if(plugin->info().engine != "C++")
218  {
219  boost::format err_msg(TE_TR("Plugin '%1%' must be unloaded with plugin engine '%2%' not by C++ plugin engine."));
220 
221  throw PluginEngineUnloadException() << ErrorDescription((err_msg % plugin->info().name % plugin->info().engine).str());
222  }
223 
224  plugin.reset();
225 }
226 
CppPlugin *(* te_get_plugin_fnct_t)(const PluginInfo &pinfo)
The type of function for plugin&#39;s entry point.
An exception indicating an error when loading a plugin.
An exception indicating an error when loading a plugin.
const std::string & id() const
It returns the id of the plugin engine.
std::pair< std::string, std::string > Resource
Definition: LibraryInfo.h:60
const std::string & name() const
It returns the name of the plugin engine.
Basic information about a plugin.
std::vector< Resource > resources
The list of resources used by plugin.
#define TE_TR(message)
It marks a string in order to get translated.
Definition: Translator.h:242
A class for handling shared libraries (DLLs, SO, DyLibs).
Definition: Library.h:73
boost::error_info< struct tag_error_description, std::string > ErrorDescription
The base type for error report messages.
std::string name
The plugin name: an internal value used to identify the plugin in the system. Must be a unique value...
static std::string absolutePath(const std::string &path)
Retrives the absolute path for the given path in UTF-8.
Definition: FileSystem.cpp:76
A base class for C++ plugins in TerraLib.
A plugin engine for plugins written in C++.
An exception indicating an error when releasing a given plugin.
A proxy class for C++ plugins.
#define TE_LOG_TRACE(message)
Use this tag in order to log a message to the TerraLib default logger with the TRACE level...
Definition: Logger.h:293
static std::string currentPath()
Retrives the current working directory path in UTF-8.
Definition: FileSystem.cpp:50
static std::string getNativeName(const std::string &name)
Given a shared library name without file extensions, prefixes and nor suffixes it will construct a li...
Definition: Library.cpp:256
Base exception class for TerraLib Core Runtime Library.
std::unique_ptr< AbstractPlugin > load(const PluginInfo &pinfo)
It loads a cpp plugin from a give PluginInfo.
void unload(std::unique_ptr< AbstractPlugin > plugin)
It unloads a cpp plugin from a give AbstractPlugin unique_ptr.