CMS 3D CMS Logo

IgPluginManager.cc

Go to the documentation of this file.
00001 //<<<<<< INCLUDES                                                       >>>>>>
00002 
00003 #include "Iguana/Framework/interface/IgPluginManager.h"
00004 #include "Iguana/Framework/interface/IgPluginInfo.h"
00005 #include "Iguana/Framework/interface/IgPluginFactoryBase.h"
00006 #include "Iguana/Framework/interface/IgModuleCache.h"
00007 #include "Iguana/Framework/interface/IgModule.h"
00008 #include "debug.h"
00009 #include "Iguana/Framework/interface/IgModuleDescriptor.h"
00010 #include "classlib/utils/SystemError.h"
00011 #include "classlib/utils/Log.h"
00012 #include <algorithm>
00013 #include <functional>
00014 #include <typeinfo>
00015 
00016 //<<<<<< PRIVATE DEFINES                                                >>>>>>
00017 //<<<<<< PRIVATE CONSTANTS                                              >>>>>>
00018 //<<<<<< PRIVATE TYPES                                                  >>>>>>
00019 
00021 class IgDirectoryByName {
00022     lat::Filename m_which;
00023 public:
00024     IgDirectoryByName (lat::Filename name) : m_which (name) {}
00025     bool operator() (const IgModuleCache *dir) {
00026         return dir->directory () == m_which;
00027     }
00028 };
00029 
00031 class IgPluginManagerDestructor {
00032     IgPluginManager     *m_manager;
00033     bool                m_destroy;
00034 
00035 public:
00036     IgPluginManagerDestructor (void)
00037         : m_manager (0),
00038 #if ! __GNUC__ || __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
00039           m_destroy (true)
00040 #else
00041           m_destroy (false)
00042 #endif
00043     {}
00044     ~IgPluginManagerDestructor (void)
00045     {
00046         if (m_destroy && m_manager)
00047         {
00048             LOG (0, trace, LFplugin_manager, "destroying plug-in manager\n" << lat::indent);
00049             delete m_manager;
00050             m_manager = 0;
00051             LOG (0, trace, LFplugin_manager, lat::undent);
00052         }
00053     }
00054 
00055     void policy (bool destroy) { m_destroy = destroy; }
00056     void object (IgPluginManager *manager) { m_manager = manager; }
00057 };
00058 
00059 //<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
00060 
00061 static IgPluginManagerDestructor s_destructor;
00062 
00063 //<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
00064 //<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
00065 //<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
00066 //<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
00067 //<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
00068 
00077 IgPluginManager *
00078 IgPluginManager::get (void)
00079 {
00080     // FIXME: Thread safety
00081     static IgPluginManager *s_db = 0;
00082     if (! s_db)
00083     {
00084         std::string path;
00085         if (const char *p = getenv ("IGUANA_PLUGINS"))
00086             path = p;
00087         else
00088             path = lat::SharedLibrary::path ();
00089 
00090         LOG (0, trace, LFplugin_manager,
00091              "initialising plugin manager with path <" << path << ">");
00092         s_db = new IgPluginManager (lat::SearchPath (path));
00093         s_destructor.object (s_db);
00094     }
00095     return s_db;
00096 }
00097 
00109 void
00110 IgPluginManager::destroyOnExit (bool destroy)
00111 { s_destructor.policy (destroy); }
00112 
00116 IgPluginManager::IgPluginManager (const lat::SearchPath &path)
00117     : m_initialised (false),
00118       m_searchPath (path)
00119 {}
00120 
00122 IgPluginManager::~IgPluginManager (void)
00123 {
00124     // Zap all the module cache directories
00125     DirectoryIterator dir = beginDirectories ();
00126     for ( ; dir != endDirectories (); ++dir)
00127         delete *dir;
00128 
00129     // Zap any factories that still remain.  The ones we still have must
00130     // be dynamically allocated and thus delete is safe -- otherwise the
00131     // global destructors would have already destructed them, causing
00132     // them to unregistered themselves from me.  (This assumes correct
00133     // library dependency linkage.)
00134     while (! m_factories.empty ())
00135         delete *m_factories.begin ();
00136 }
00137 
00153 void
00154 IgPluginManager::initialise (void)
00155 {
00156     if (m_initialised) return;
00157     m_initialised = true;
00158 
00159     lat::SearchPath::const_iterator dir = m_searchPath.begin ();
00160     for ( ; dir != m_searchPath.end (); ++dir)
00161     {
00162         // Ignore directories that do not exist.  Also ignore
00163         // empty directory components ("foo::bar") as they are
00164         // unlikely to be intended.  This is unlike normal unix
00165         // behaviour where "::" really means ":.:", but avoids
00166         // a common problem from appending to IGUANA_PLUGINS as
00167         // $IGUANA_PLUGINS:foo when SEAL_PLUGINS is not set.  If
00168         // user really wants to have "." in the path -- and that
00169         // is exceedingly unlikely -- they can always do so
00170         // explicitly.
00171         if (! dir->empty ())
00172         {
00173             try {
00174                 m_directories.push_back (new IgModuleCache (this, *dir));
00175             } catch (lat::Error &error) {
00176                 LOG (0, warning, LFplugin_manager, lat::undent << lat::undent
00177                      << "directory " << *dir << " ignored: "
00178                      << typeid(error).name () << " ("
00179                      << error.explain ().c_str () << ")\n");
00180                 continue;
00181             }
00182         }
00183     }
00184 
00185     rebuild ();
00186 }
00187 
00191 
00192 void
00193 IgPluginManager::addInfo (IgPluginInfo *info)
00194 {
00195     // This method is called by #IgModule when it receives a new info
00196     // object.  We find the factory that matches the info object's
00197     // category, and then route the call to the factory so it can
00198     // add the info object to its list of available plug-ins.
00199     //
00200     // #IgModule is notified in turn by #IgPluginInfo constructors, or
00201     // more specifically, the finish() method that is called by the
00202     // IgPluginInfo subclass at the end of its constructor.  The
00203     // module just routes the call to us.
00204     //
00205     // The #IgPluginInfo can come into existence in one of two ways:
00206     // created by the module query, or reincarnated from a cache by
00207     // request of the factory when it is being constructed.
00208     //
00209     // The factory matching the info object must already exist, there
00210     // is no way to get here without that being the case.  However it
00211     // may still be under construction, which is one reason why the
00212     // call is propagated through base classes and not directly to the
00213     // factory from the IgPluginInfo derived class; another reason is
00214     // to keep knowledge about factories in the plug-in manager and
00215     // out of #IgModule.
00216     IgPluginFactoryBase *factory = findFactory (info->category ());
00217     ASSERT (factory);
00218     factory->addInfo (info);
00219 }
00220 
00221 /* Route a dying plug-in info notification to the appropriate factory. */
00222 void
00223 IgPluginManager::removeInfo (IgPluginInfo *info)
00224 {
00225     // This method is called by #IgModule when a #IgPluginInfo object is
00226     // being destructed, with some processing in #IgModule first.  We
00227     // find the factory matching the info object category, and route
00228     // the call to the factory so it can remove the info from it's
00229     // list.  Knowledge about the info object remains in raw cached
00230     // form in #IgModule unless the purpose is to purge the cache.
00231     //
00232     // #IgPluginInfo objects die in one of two ways: either because the
00233     // factory is going out of scope -- for instance because it itself
00234     // was in a dynamically loaded module that is getting unloaded --
00235     // or because the #IgModule object deletes it.  The latter can
00236     // happen for a variety reasons, for example when re-querying a
00237     // module, when module is marked bad, or when the module object
00238     // is deleted as a part of a cache refresh.
00239     //
00240     // By definition the factory already exists, info objects can be
00241     // created only with the factory present, and the factory deletes
00242     // its info objects before dying itself.  The call is routed here
00243     // in order to keep knowledge about factories here, as well as
00244     // for symmetry with the other info-related registration methods.
00245     IgPluginFactoryBase *factory = findFactory (info->category ());
00246     ASSERT (factory);
00247     factory->removeInfo (info);
00248 }
00249 
00250 /* Route a request to restore an info object from raw cached form to
00251    the appropriate factory.  The info item's category, the first token
00252    in the cached data, is expected to be the factory registration name.  */
00253 void
00254 IgPluginManager::restore (IgModule *module, IgModuleDescriptor *from)
00255 {
00256     // This method is called by #IgModule when reading back a cache
00257     // to inform a factory to create a #IgPluginInfo from cached form.
00258     // We look for a factory matching the info object category; the
00259     // convention is that the first token of the cached info object
00260     // data must be the category of the info object and the name of
00261     // the factory.  If such a factory is registered, we pass it the
00262     // cache data; it will instantiate an appropriate info object
00263     // from it, which will then end up calling #addInfo().
00264     //
00265     // If no factory is currently registered, the call is ignored.
00266     // In that case, #IgModule will retain the raw cached data, and
00267     // when the factory is instantiated, it will rebuild the info
00268     // objects from that (see #IgPluginFactoryBase::rebuild()).  In
00269     // that case the calls will not go through this method; only
00270     // #addInfo() is used as the info objects are instantiated.
00271     ASSERT (from);
00272     ASSERT (from->tokens () >= 2);
00273     if (IgPluginFactoryBase *factory = findFactory (from->token (0)))
00274         factory->restore (module, from);
00275 }
00276 
00280 
00284 void
00285 IgPluginManager::addFactory (IgPluginFactoryBase *factory)
00286 {
00287     // FIXME: allow factories to be registered to the database, then
00288     // notify them on each refresh (and when they are added).  The
00289     // factories should be accessed via XyzDB::get () which gets the
00290     // global database and registers an instance of the factory into it.
00291     m_factories.push_back (factory);
00292 }
00293 
00298 void
00299 IgPluginManager::removeFactory (IgPluginFactoryBase *factory)
00300 {
00301     FactoryIterator pos = std::find (m_factories.begin (), m_factories.end (), factory);
00302     ASSERT (pos != m_factories.end ());
00303     m_factories.erase (pos);
00304 }
00305 
00309 IgPluginFactoryBase *
00310 IgPluginManager::findFactory (const std::string &name)
00311 {
00312     FactoryIterator pos = m_factories.begin ();
00313     while (pos != m_factories.end () && (*pos)->category () != name)
00314         ++pos;
00315 
00316     return pos != m_factories.end () ? *pos : 0;
00317 }
00318 
00322 
00328 void
00329 IgPluginManager::rebuild (void)
00330 {
00331     ModuleMap                   modules;
00332     IgModuleCache::Iterator     module;
00333     DirectoryIterator           dir;
00334 
00335     // Collect modules into a map
00336     for (dir = beginDirectories (); dir != endDirectories (); ++dir)
00337         for (module = (*dir)->begin (); module != (*dir)->end (); ++module)
00338             if (! modules.count ((*module)->libraryName ()))
00339                 modules [(*module)->libraryName ()] = *module;
00340 
00341     // Put the information back
00342     m_modules.swap (modules);
00343 
00344     // There's no need to update custom factories.  Refreshing the modules
00345     // caused them to be re-queried, which caused each module to blast
00346     // away their caches and existing infos, which caused all factories to
00347     // remove their database of those infos, plus the re-query caused
00348     // all necessary new infos to be created.
00349 }
00350 
00361 void
00362 IgPluginManager::refresh (void)
00363 {
00364     DirectoryIterator dir = beginDirectories ();
00365     for ( ; dir != endDirectories (); ++dir)
00366         (*dir)->refresh ();
00367 
00368     rebuild ();
00369 }
00370 
00374 
00375 IgPluginManager::DirectoryIterator
00376 IgPluginManager::beginDirectories (void) const
00377 { return m_directories.begin (); }
00378 
00380 IgPluginManager::DirectoryIterator
00381 IgPluginManager::endDirectories (void) const
00382 { return m_directories.end (); }
00383 
00385 IgPluginManager::DirectoryIterator
00386 IgPluginManager::locateDirectory (const lat::Filename &name) const
00387 {
00388     return std::find_if (beginDirectories (), endDirectories (),
00389                          IgDirectoryByName (name));
00390 }
00391 
00395 IgModuleCache *
00396 IgPluginManager::directory (const lat::Filename &name) const
00397 {
00398     DirectoryIterator pos = locateDirectory (name);
00399     return pos != endDirectories () ? *pos : 0;
00400 }
00401 
00403 
00406 IgPluginManager::ModuleIterator
00407 IgPluginManager::beginModules (void) const
00408 { return ModuleIterator (m_modules.begin ()); }
00409 
00413 IgPluginManager::ModuleIterator
00414 IgPluginManager::endModules (void) const
00415 { return ModuleIterator (m_modules.end ()); }
00416 
00420 IgPluginManager::ModuleIterator
00421 IgPluginManager::locateModule (const lat::Filename &libraryName) const
00422 { return ModuleIterator (m_modules.find (libraryName)); }
00423 
00428 IgModule *
00429 IgPluginManager::module (const lat::Filename &libraryName) const
00430 {
00431     ModuleIterator pos = locateModule (libraryName);
00432     return pos != endModules () ? *pos : 0;
00433 }
00434 
00436 
00437 void
00438 IgPluginManager::addFeedback (FeedbackCB callback)
00439 { m_feedbacks.push_back (callback); }
00440 
00442 void
00443 IgPluginManager::removeFeedback (FeedbackCB callback)
00444 { m_feedbacks.remove (callback); }
00445 
00447 void
00448 IgPluginManager::feedback (FeedbackData data)
00449 {
00450    FeedbackIterator i;
00451    for (i = m_feedbacks.begin (); i != m_feedbacks.end (); ++i)
00452         (*i) (data);
00453 }
00454 
00456 void
00457 IgPluginManager::feedback (FeedbackCode code,
00458                            const lat::Filename &scope,
00459                            lat::Error *error /* = 0 */)
00460 { feedback (FeedbackData (code, (std::string) scope, error)); }
00461 
00463 void
00464 IgPluginManager::feedback (FeedbackCode code,
00465                            const std::string &scope,
00466                            lat::Error *error /* = 0 */)
00467 { feedback (FeedbackData (code, scope, error)); }

Generated on Tue Jun 9 17:38:29 2009 for CMSSW by  doxygen 1.5.4