OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
RegistrationContext.cpp
Go to the documentation of this file.
1 
12 // Copyright 2014 Sensics, Inc.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "License");
15 // you may not use this file except in compliance with the License.
16 // You may obtain a copy of the License at
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 // See the License for the specific language governing permissions and
24 // limitations under the License.
25 
26 #ifndef __ANDROID__
27 #define OSVR_DEV_VERBOSE_DISABLE
28 #endif
29 
30 // Internal Includes
32 
36 #include <osvr/Util/Log.h>
37 #include <osvr/Util/Verbosity.h>
38 
39 // Library/third-party includes
40 #include <boost/algorithm/string/predicate.hpp>
41 #include <boost/filesystem.hpp>
42 #include <boost/noncopyable.hpp>
43 #include <boost/range/adaptor/map.hpp>
44 #include <boost/range/adaptor/reversed.hpp>
45 #include <libfunctionality/LoadPlugin.h>
46 
47 // Standard includes
48 #include <algorithm>
49 #include <iterator>
50 
51 namespace osvr {
52 namespace pluginhost {
53  static const auto PLUGIN_HOST_LOGGER_NAME = "PluginHost";
54 #ifdef _MSC_VER
55  static const auto PLUGIN_HOST_DEBUG_SUFFIX = ".debug";
56 #endif
57  namespace fs = boost::filesystem;
58 
59  struct RegistrationContext::Impl : private boost::noncopyable {
61  Impl() : pluginPaths(pluginhost::getPluginSearchPath()) {}
62 
63  const std::vector<std::string> pluginPaths;
64  };
65 
67  : m_impl(new Impl),
68  m_logger(util::log::make_logger(PLUGIN_HOST_LOGGER_NAME)) {}
69 
71  // Reset the plugins in reverse order.
72  for (auto &ptr : m_regMap | boost::adaptors::map_values |
73  boost::adaptors::reversed) {
74  ptr.reset();
75  }
76  }
77 
78  template <typename MapType>
79  static inline bool isPluginLoaded(MapType const &regMap,
80  std::string const &pluginName) {
81  return (regMap.find(pluginName) != end(regMap));
82  }
83 
86  static inline bool tryLoadingPlugin(util::log::Logger &log,
87  libfunc::PluginHandle &plugin,
88  std::string const &name,
90  bool shouldRethrow = false) {
91 #if defined(_MSC_VER) && !defined(NDEBUG)
92  // Visual C++ debug runtime: we append to the plugin name.
93  const std::string decoratedPluginName = name + PLUGIN_HOST_DEBUG_SUFFIX;
94 #else
95  const std::string &decoratedPluginName = name;
96 #endif
97  log.debug() << "Trying to load a plugin with the name "
98  << decoratedPluginName;
99  try {
100  plugin = libfunc::loadPluginByName(decoratedPluginName, ctx);
101  return true;
102  } catch (std::runtime_error const &e) {
103  log.debug() << "Failed: " << e.what();
104  if (shouldRethrow) {
105  throw;
106  }
107  return false;
108  } catch (...) {
109  throw;
110  }
111  }
112 
113  void RegistrationContext::loadPlugin(std::string const &pluginName) {
114  if (isPluginLoaded(m_regMap, pluginName)) {
115  throw std::runtime_error("Already loaded a plugin named " +
116  pluginName);
117  }
118 
119  PluginRegPtr pluginReg(
121  pluginReg->setParent(*this);
122 
123  bool success = false;
124  libfunc::PluginHandle plugin;
125  auto ctx = pluginReg->extractOpaquePointer();
126  const std::string pluginPathName =
127  pluginhost::findPlugin(m_impl->pluginPaths, pluginName);
128  if (pluginPathName.empty()) {
129  // was the plugin pre-loaded or statically linked? Try loading
130  // it by name.
131  success = tryLoadingPlugin(*m_logger, plugin, pluginName, ctx);
132  if (!success) {
133  throw std::runtime_error("Could not find plugin named " +
134  pluginName);
135  }
136  }
137 
138  if (!success) {
139  const auto pluginPathNameNoExt =
140  (fs::path(pluginPathName).parent_path() /
141  fs::path(pluginPathName).stem())
142  .generic_string();
143 
144  success =
145  tryLoadingPlugin(*m_logger, plugin, pluginPathName, ctx) ||
146  tryLoadingPlugin(*m_logger, plugin, pluginPathNameNoExt, ctx,
147  true);
148  if (!success) {
149  throw std::runtime_error(
150  "Unusual error occurred trying to load plugin named " +
151  pluginName);
152  }
153  }
154  pluginReg->takePluginHandle(plugin);
156  }
157 
159  // Build a list of all the plugins we can find
160  auto pluginPathNames = pluginhost::getAllFilesWithExt(
161  m_impl->pluginPaths, OSVR_PLUGIN_EXTENSION);
162 
163  // Load all of the non-.manualload plugins
164  for (const auto &plugin : pluginPathNames) {
165  m_logger->debug() << "Examining plugin '" << plugin << "'...";
166  const auto pluginBaseName =
167  fs::path(plugin).filename().stem().generic_string();
168  if (boost::iends_with(pluginBaseName, OSVR_PLUGIN_IGNORE_SUFFIX)) {
169  m_logger->debug() << "Ignoring manual-load plugin: "
170  << pluginBaseName;
171  continue;
172  }
173 
174 #if defined(_MSC_VER)
175  // Visual C++ debug runtime: we append to the plugin name. Must only
176  // load debug plugins iff we're a debug server
177  const auto isDebugRuntimePlugin =
178  boost::iends_with(pluginBaseName, PLUGIN_HOST_DEBUG_SUFFIX);
179 #if defined(NDEBUG)
180  if (isDebugRuntimePlugin) {
182  m_logger->debug() << "Ignoring debug-runtime plugin: "
183  << pluginBaseName;
184  continue;
185  }
186 #else
187  if (!isDebugRuntimePlugin) {
189  m_logger->debug() << "Ignoring non-debug-runtime plugin: "
190  << pluginBaseName;
191  continue;
192  }
193 #endif // NDEBUG
194 #endif // _MSC_VER
195 
196  try {
197  loadPlugin(pluginBaseName);
198  m_logger->debug() << "Successfully loaded plugin: "
199  << pluginBaseName;
200  } catch (const std::exception &e) {
201  m_logger->warn() << "Failed to load plugin " << pluginBaseName
202  << ": " << e.what();
203  } catch (...) {
204  m_logger->warn() << "Failed to load plugin " << pluginBaseName
205  << ": Unknown error.";
206  }
207  }
208  }
209 
213  ctx->setParent(*this);
214 
215  m_regMap.insert(std::make_pair(ctx->getName(), ctx));
216  }
217 
219  for (auto &pluginPtr : m_regMap | boost::adaptors::map_values) {
220  pluginPtr->triggerHardwareDetectCallbacks();
221  }
222  }
223 
224  void
225  RegistrationContext::instantiateDriver(const std::string &pluginName,
226  const std::string &driverName,
227  const std::string &params) const {
228  auto pluginIt = m_regMap.find(pluginName);
229  if (pluginIt == end(m_regMap)) {
230  throw std::runtime_error("Could not find plugin named " +
231  pluginName);
232  }
233  pluginIt->second->instantiateDriver(driverName, params);
234  }
235 
237 
238  util::AnyMap const &RegistrationContext::data() const { return m_data; }
239 } // namespace pluginhost
240 } // namespace osvr
void loadPlugins()
Load all detected plugins except those with a .manualload suffix.
Header for basic internal log reference. To actually log to the produced loggers, include
~RegistrationContext()
Destructor responsible for destroying plugins in reverse order.
A data structure storing "any" by name, to reduce coupling.
Definition: AnyMap.h:42
Impl()
constructor - creates and caches the plugin search path
FileList getAllFilesWithExt(SearchPath const &dirPath, const std::string &ext)
Get list of files inside the directory with given extension.
Definition: SearchPath.cpp:124
void adoptPluginRegistrationContext(PluginRegPtr ctx)
Assume ownership of a plugin-specific registration context created and initialized outside of loadPlu...
util::AnyMap & data()
Access the data storage map.
SearchPath getPluginSearchPath()
Find a place where to look for plugins.
Definition: SearchPath.cpp:47
An object allowing you to log messages with a given log source name.
Definition: Logger.h:67
Header.
void triggerHardwareDetect()
Trigger any registered hardware detect callbacks.
Internal, configured header file for verbosity macros.
OSVR_EXTERN_C_BEGIN typedef void * OSVR_PluginRegContext
A context pointer passed in to your plugin's entry point and other locations of control flow transfer...
shared_ptr< PluginSpecificRegistrationContextImpl > PluginRegPtr
Pointer with ownership semantics for cleanup of plugins.
Definition: PluginRegPtr.h:33
static PluginRegPtr create(std::string const &name)
Factory function that creates a plugin-specific registration context. Ownership is transferred to the...
std::string findPlugin(SearchPath const &searchPaths, const std::string &pluginName)
Given the name of a plugin, find the full path to the plugin library.
Definition: SearchPath.cpp:151
void instantiateDriver(const std::string &pluginName, const std::string &driverName, const std::string &params=std::string()) const
Call a driver instantiation callback for the given plugin name and driver name.
Auto-generated configuration header - do not edit!