fw4spl
Runtime.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2017.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwRuntime/Runtime.hpp"
8 
9 #include "fwRuntime/ConfigurationElement.hpp"
10 #include "fwRuntime/ExecutableFactory.hpp"
11 #include "fwRuntime/Extension.hpp"
12 #include "fwRuntime/ExtensionPoint.hpp"
13 #include "fwRuntime/IExecutable.hpp"
14 #include "fwRuntime/io/BundleDescriptorReader.hpp"
15 #include "fwRuntime/IPlugin.hpp"
16 
17 #include <boost/filesystem/operations.hpp>
18 
19 #include <limits.h>
20 
21 #include <algorithm>
22 #include <cassert>
23 #include <functional>
24 
25 #ifdef _WIN32
26 #include <WinBase.h>
27 #elif __APPLE__
28 #include <mach-o/dyld.h>
29 #else
30 #include <unistd.h>
31 #endif
32 
33 namespace fwRuntime
34 {
35 
36 //------------------------------------------------------------------------------
37 
38 std::shared_ptr<Runtime> Runtime::m_instance;
39 
40 //------------------------------------------------------------------------------
41 
42 Runtime::Runtime()
43 {
44  // Get executable location on 'progPath'
45 #ifdef _WIN32
46  char progPath[MAX_PATH];
47  if( GetModuleFileName(NULL, progPath, MAX_PATH) == 0 )
48 #elif __APPLE__
49  char progPath[PATH_MAX];
50  uint32_t size = PATH_MAX;
51  if( _NSGetExecutablePath(progPath, &size) != 0 )
52 #else
53  char progPath[PATH_MAX];
54  ssize_t len = readlink("/proc/self/exe", progPath, PATH_MAX-1);
55  if ( len != -1 )
56  {
57  progPath[len] = '\0';
58  }
59  if ( len == -1 )
60 #endif
61  // If there is an system error, use the current path
62  {
63  OSLM_WARN("Cannot guess the path of the executable, it's required to set the working directory. "
64  "Current working directory is used");
65  m_workingPath = ::boost::filesystem::current_path();
66  }
67  else
68  {
69  m_workingPath = progPath;
70  // The program location is 'path/bin/executable', real working path is 'path'
71  m_workingPath = m_workingPath.normalize().parent_path().parent_path();
72  }
73 }
74 
75 //------------------------------------------------------------------------------
76 
78 {
79 }
80 
81 //------------------------------------------------------------------------------
82 
83 void Runtime::addBundle( std::shared_ptr< Bundle > bundle )
84 {
85  m_bundles.insert( bundle );
86  std::for_each( bundle->extensionsBegin(), bundle->extensionsEnd(),
87  std::bind(&Runtime::addExtension, this, std::placeholders::_1));
88  std::for_each( bundle->extensionPointsBegin(), bundle->extensionPointsEnd(),
89  std::bind(&Runtime::addExtensionPoint, this, std::placeholders::_1));
90  std::for_each( bundle->executableFactoriesBegin(), bundle->executableFactoriesEnd(),
91  std::bind(&Runtime::addExecutableFactory, this, std::placeholders::_1));
92 }
93 
94 //------------------------------------------------------------------------------
95 
96 void Runtime::unregisterBundle( std::shared_ptr< Bundle > bundle )
97 {
98  FwCoreNotUsedMacro(bundle);
99 }
100 
101 //------------------------------------------------------------------------------
102 
103 void Runtime::addBundles( const ::boost::filesystem::path& repository )
104 {
105  try
106  {
107  using ::fwRuntime::io::BundleDescriptorReader;
108  const BundleDescriptorReader::BundleContainer bundles = BundleDescriptorReader::createBundles( repository );
109  std::for_each( bundles.begin(), bundles.end(), std::bind(&Runtime::addBundle, this, std::placeholders::_1) );
110  }
111  catch(const std::exception& exception)
112  {
113  throw RuntimeException( std::string("Error while adding bundles. ") + exception.what() );
114  }
115 }
116 
117 //------------------------------------------------------------------------------
118 
120 {
121  // Bundles location
122  const auto location = this->getWorkingPath() / BUNDLE_RC_PREFIX;
123 
124  SLM_ASSERT("Default Bundles location not found: " + location.string(), ::boost::filesystem::exists(location));
125 
126  // Read bundles
127  this->addBundles(location);
128  SLM_ASSERT("Couldn't load any bundle from path: " + location.string(), this->bundlesBegin() != this->bundlesEnd());
129 }
130 
131 //------------------------------------------------------------------------------
132 
134 {
135  return m_bundles.begin();
136 }
137 
138 //------------------------------------------------------------------------------
139 
141 {
142  return m_bundles.end();
143 }
144 
145 //------------------------------------------------------------------------------
146 
147 void Runtime::addExecutableFactory( std::shared_ptr< ExecutableFactory > factory )
148 {
149  // Ensures no registered factory has the same identifier.
150  const std::string type( factory->getType() );
151  if( this->findExecutableFactory(type) != 0 )
152  {
153  throw RuntimeException(type + ": type already used by an executable factory.");
154  }
155  // Stores the executable factory.
156  m_executableFactories.insert( factory );
157 }
158 
159 //------------------------------------------------------------------------------
160 
161 void Runtime::unregisterExecutableFactory( std::shared_ptr< ExecutableFactory > factory )
162 {
163  // Ensures no registered factory has the same identifier.
164  const std::string type( factory->getType() );
165  SLM_WARN_IF("ExecutableFactory Type " + type + " not found.", this->findExecutableFactory(type) == 0 );
166  // Removes the executable factory.
167  m_executableFactories.erase(factory);
168 }
169 
170 //------------------------------------------------------------------------------
171 
172 std::shared_ptr< ExecutableFactory > Runtime::findExecutableFactory( const std::string& type ) const
173 {
174  std::shared_ptr< ExecutableFactory > resFactory;
175  for(const ExecutableFactoryContainer::value_type& factory : m_executableFactories)
176  {
177  if(factory->getType() == type && factory->isEnable())
178  {
179  resFactory = factory;
180  break;
181  }
182  }
183  return resFactory;
184 }
185 
186 //------------------------------------------------------------------------------
187 
188 void Runtime::addExtension( std::shared_ptr<Extension> extension)
189 {
190  // Asserts no registered extension has the same identifier.
191  const std::string identifier(extension->getIdentifier());
192  if( !identifier.empty() && this->findExtension(identifier) != 0 )
193  {
194  throw RuntimeException(identifier + ": identifier already used by a registered extension.");
195  }
196  // Stores the extension.
197  m_extensions.insert( extension );
198 }
199 
200 //------------------------------------------------------------------------------
201 
202 void Runtime::unregisterExtension( std::shared_ptr<Extension> extension)
203 {
204  // Asserts no registered extension has the same identifier.
205  const std::string identifier(extension->getIdentifier());
206  SLM_WARN_IF("Extension " + identifier + " not found.",
207  !identifier.empty() && this->findExtension(identifier) == 0 );
208  // Removes the extension.
209  m_extensions.erase( extension );
210 }
211 
212 //------------------------------------------------------------------------------
213 
215 {
216  return m_extensions.begin();
217 }
218 
219 //------------------------------------------------------------------------------
220 
222 {
223  return m_extensions.end();
224 }
225 
226 //------------------------------------------------------------------------------
227 
228 void Runtime::addExtensionPoint( std::shared_ptr<ExtensionPoint> point)
229 {
230  // Asserts no registered extension point has the same identifier.
231  const std::string identifier(point->getIdentifier());
232  if( this->findExtensionPoint(identifier) != 0)
233  {
234  throw RuntimeException(identifier + ": identifier already used by a registered extension point.");
235  }
236  // Stores the extension.
237  m_extensionPoints.insert(point);
238 }
239 
240 //------------------------------------------------------------------------------
241 
242 void Runtime::unregisterExtensionPoint( std::shared_ptr<ExtensionPoint> point)
243 {
244  // Asserts no registered extension point has the same identifier.
245  const std::string identifier(point->getIdentifier());
246  SLM_WARN_IF("ExtensionPoint " + identifier + " not found.",
247  this->findExtensionPoint(identifier) == 0);
248  // Removes the extension.
249  m_extensionPoints.erase(point);
250 }
251 
252 //------------------------------------------------------------------------------
253 
254 std::shared_ptr< Bundle > Runtime::findBundle( const std::string& identifier, const Version& version ) const
255 {
256  std::shared_ptr<Bundle> resBundle;
257  for(const std::shared_ptr<Bundle>& bundle : m_bundles)
258  {
259  if(bundle->getIdentifier() == identifier && bundle->getVersion() == version)
260  {
261  resBundle = bundle;
262  break;
263  }
264  }
265  return resBundle;
266 }
267 
268 //------------------------------------------------------------------------------
269 
270 std::shared_ptr< Bundle > Runtime::findEnabledBundle( const std::string& identifier, const Version& version ) const
271 {
272  std::shared_ptr<Bundle> resBundle;
273  for(const std::shared_ptr<Bundle>& bundle : m_bundles)
274  {
275  if(bundle->getIdentifier() == identifier && bundle->getVersion() == version && bundle->isEnable())
276  {
277  resBundle = bundle;
278  break;
279  }
280  }
281  return resBundle;
282 }
283 
284 //------------------------------------------------------------------------------
285 
287 {
288  if(m_instance.get() == 0)
289  {
290  m_instance = std::shared_ptr<Runtime>(new Runtime());
291  }
292  return m_instance.get();
293 }
294 
295 //------------------------------------------------------------------------------
296 
297 std::shared_ptr<Extension> Runtime::findExtension( const std::string& identifier ) const
298 {
299  std::shared_ptr<Extension> resExtension;
300  for(const ExtensionContainer::value_type& extension : m_extensions)
301  {
302  if(extension->getIdentifier() == identifier && extension->isEnable())
303  {
304  resExtension = extension;
305  break;
306  }
307  }
308  return resExtension;
309 }
310 
311 //------------------------------------------------------------------------------
312 
313 std::shared_ptr<ExtensionPoint> Runtime::findExtensionPoint( const std::string& identifier ) const
314 {
315  std::shared_ptr<ExtensionPoint> resExtensionPoint;
316  for(const ExtensionPointContainer::value_type& extensionPoint : m_extensionPoints)
317  {
318  if(extensionPoint->getIdentifier() == identifier && extensionPoint->isEnable())
319  {
320  resExtensionPoint = extensionPoint;
321  break;
322  }
323  }
324  return resExtensionPoint;
325 }
326 
327 //------------------------------------------------------------------------------
328 
330 {
331  std::shared_ptr< ExecutableFactory > factory;
332 
333  // Retrieves the executable factory.
334  factory = this->findExecutableFactory( type );
335  if( factory == 0 )
336  {
337  throw RuntimeException( type + ": no executable factory found for that type." );
338  }
339 
340  // Creates the executable instance
341  IExecutable* result( factory->createExecutable() );
342  result->setBundle( factory->getBundle() );
343 
344  // Job's done.
345  return result;
346 }
347 
348 //------------------------------------------------------------------------------
349 
350 IExecutable* Runtime::createExecutableInstance( const std::string& type,
351  ConfigurationElement::sptr configurationElement )
352 {
353  std::shared_ptr< ExecutableFactory > factory;
354 
355  // Retrieves the executable factory.
356  factory = this->findExecutableFactory( type );
357 
358  // If there is no factory has been found, it is possible that
359  // it has not been registered since the bundle of the given configuration element
360  // is not started.
361  // So we start that bundle and look for the executable factory one more type.
362  if( factory == 0)
363  {
364  configurationElement->getBundle()->start();
365  factory = this->findExecutableFactory( type );
366  }
367 
368  // If we still have not found any executable factory, then notify the problem.
369  if( factory == 0 )
370  {
371  throw RuntimeException( type + ": no executable factory found for that type." );
372  }
373 
374  // Creates the executable instance
375  IExecutable* result( 0 );
376  try
377  {
378  factory->getBundle()->start();
379  result = factory->createExecutable();
380 
381  result->setBundle( factory->getBundle() );
382  result->setInitializationData( configurationElement );
383  }
384  catch( const std::exception& e )
385  {
386  std::string message( "Unable to create an executable instance. " );
387  throw RuntimeException( message + e.what() );
388  }
389  // Job's done.
390  return result;
391 }
392 
393 //------------------------------------------------------------------------------
394 
395 void Runtime::setWorkingPath(const ::boost::filesystem::path& workingPath)
396 {
397  m_workingPath = workingPath;
398 }
399 
400 //------------------------------------------------------------------------------
401 
402 ::boost::filesystem::path Runtime::getWorkingPath() const
403 {
404  return m_workingPath;
405 }
406 
407 //------------------------------------------------------------------------------
408 
409 } // namespace fwRuntime
static FWRUNTIME_API Runtime * getDefault()
Retrieves the default runtime instance.
Definition: Runtime.cpp:286
Defines the runtime class.
Definition: Runtime.hpp:37
virtual void setInitializationData(const std::shared_ptr< ConfigurationElement > configuration) noexcept=0
Initializes the executable instance with the specified configuration element.
ExtensionContainer::iterator ExtensionIterator
Defines the extension container type.
Definition: Runtime.hpp:51
FWRUNTIME_API void addExtension(std::shared_ptr< Extension > extension)
Registers a new extension.
Definition: Runtime.cpp:188
FWRUNTIME_API ExtensionIterator extensionsEnd()
Retrieves the iterator on the end of the extension collection.
Definition: Runtime.cpp:221
Defines the runtime exception class.
FWRUNTIME_API BundleIterator bundlesBegin()
Retrieves the iterator on the begining of the bundle collection.
Definition: Runtime.cpp:133
FWRUNTIME_API std::shared_ptr< Bundle > findEnabledBundle(const std::string &identifier, const Version &version=Version()) const
Retrieves the enabled bundle for the specified idenfier.
Definition: Runtime.cpp:270
FWRUNTIME_API IExecutable * createExecutableInstance(const std::string &type)
Create an instance of the given executable object type.
Definition: Runtime.cpp:329
FWRUNTIME_API void unregisterExecutableFactory(std::shared_ptr< ExecutableFactory > factory)
Unregister a new executable factory instance to the runtime system.
Definition: Runtime.cpp:161
FWRUNTIME_API std::shared_ptr< Extension > findExtension(const std::string &identifier) const
Retrieves the extension instance matching the specified identifier.
Definition: Runtime.cpp:297
FWRUNTIME_API void setWorkingPath(const ::boost::filesystem::path &workingPath)
Set the working path where Bundles and share folder are located.
Definition: Runtime.cpp:395
FWRUNTIME_API ExtensionIterator extensionsBegin()
Retrieves the iterator on the beginning of the extension collection.
Definition: Runtime.cpp:214
FWRUNTIME_API void addBundle(std::shared_ptr< Bundle > bundle)
Adds a new bundle instance to the runtime system.
Definition: Runtime.cpp:83
Defines the base executable interface.An executable object is an instance created by an extension poi...
Definition: IExecutable.hpp:41
FWRUNTIME_API void unregisterBundle(std::shared_ptr< Bundle > bundle)
Unregister a bundle instance to the runtime system.
Definition: Runtime.cpp:96
FWRUNTIME_API BundleIterator bundlesEnd()
Retrieves the iterator on the end of the bundle collection.
Definition: Runtime.cpp:140
Contains fwAtomsFilter::factory utilities.
FWRUNTIME_API std::shared_ptr< Bundle > findBundle(const std::string &identifier, const Version &version=Version()) const
Retrieves the bundle for the specified idenfier.
Definition: Runtime.cpp:254
The namespace fwRuntime contains classes to manage bundle, configuration element, extension point in ...
FWRUNTIME_API std::shared_ptr< ExtensionPoint > findExtensionPoint(const std::string &identifier) const
Retrieves the extension point instance matching the specified identifier.
Definition: Runtime.cpp:313
FWRUNTIME_API std::shared_ptr< ExecutableFactory > findExecutableFactory(const std::string &type) const
Retrieves the executable factory for the given identifier.
Definition: Runtime.cpp:172
#define OSLM_WARN(message)
Definition: spyLog.hpp:263
~Runtime()
Destructor : does nothing.
Definition: Runtime.cpp:77
#define SLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:308
FWRUNTIME_API void addExecutableFactory(std::shared_ptr< ExecutableFactory > factory)
Adds a new executable factory instance to the runtime system.
Definition: Runtime.cpp:147
virtual void setBundle(std::shared_ptr< Bundle > bundle)=0
Updates the bundle the executable originates from.
FWRUNTIME_API void addBundles(const ::boost::filesystem::path &repository)
Adds all bundle found in the given path.
Definition: Runtime.cpp:103
BundleContainer::iterator BundleIterator
Defines the bundle container iterator type.
Definition: Runtime.hpp:47
Holds version information for libraries and bundles.
FWRUNTIME_API void unregisterExtensionPoint(std::shared_ptr< ExtensionPoint > point)
Unregister a new extension point.
Definition: Runtime.cpp:242
FWRUNTIME_API void addDefaultBundles()
Adds all bundle found at the default location.
Definition: Runtime.cpp:119
FWRUNTIME_API void addExtensionPoint(std::shared_ptr< ExtensionPoint > point)
Registers a new extension point.
Definition: Runtime.cpp:228
#define SLM_WARN_IF(message, cond)
Definition: spyLog.hpp:265
FWRUNTIME_API void unregisterExtension(std::shared_ptr< Extension > extension)
Unregister a new extension.
Definition: Runtime.cpp:202
FWRUNTIME_API::boost::filesystem::path getWorkingPath() const
Get the path where Bundles and share folder are located.
Definition: Runtime.cpp:402