00001
00002
00003 #include "Iguana/Framework/interface/IgModule.h"
00004 #include "Iguana/Framework/interface/IgModuleDef.h"
00005 #include "Iguana/Framework/interface/IgModuleDescriptor.h"
00006 #include "Iguana/Framework/interface/IgPluginCapabilities.h"
00007 #include "Iguana/Framework/interface/IgPluginManager.h"
00008 #include "Iguana/Framework/interface/IgPluginInfo.h"
00009 #include "Iguana/Framework/interface/IgPluginError.h"
00010 #include "debug.h"
00011 #include "classlib/utils/SharedLibrary.h"
00012 #include "classlib/utils/SharedLibraryError.h"
00013 #include "classlib/utils/ShellEnvironment.h"
00014 #include "classlib/iobase/Filename.h"
00015 #include "classlib/utils/DebugAids.h"
00016 #include "classlib/utils/Log.h"
00017 #include <algorithm>
00018
00019
00020
00021
00022
00023
00024
00025
00026 const char IgModule::s_modEntryPoint [] = "IGUANA_MODULE";
00027 const char IgModule::s_capEntryPoint [] = "IGUANA_CAPABILITIES";
00028 const char IgModule::s_tag [] = "module";
00029
00030
00031
00032
00033
00034 IgModule *
00035 IgModule::builtin (void)
00036 {
00037 static IgModule *myself = new IgModule (IgPluginManager::get (),
00038 "" ,
00039 "0", "good");
00040 return myself;
00041 }
00042
00043 IgModule::IgModule (IgPluginManager *manager,
00044 const lat::Filename &libraryName,
00045 const std::string &time,
00046 const std::string &flag)
00047 : m_manager (manager),
00048 m_libraryName (libraryName),
00049 m_library (0),
00050 m_cache (0),
00051 m_time (strtoul (time.c_str (), 0, 10)),
00052 m_bad (flag != "good"),
00053 m_attached (libraryName.empty ()),
00054 m_definition (0)
00055 {
00056 ASSERT (flag == "good" || flag == "bad");
00057 ASSERT (! time.empty ());
00058 LOG (0, trace, LFplugin_manager,
00059 "constructing module for library `" << m_libraryName << "'\n");
00060 makeCache ();
00061 }
00062
00063 IgModule::~IgModule (void)
00064 {
00065 LOG (0, trace, LFplugin_manager,
00066 "destroying module for library `" << m_libraryName << "'\n");
00067
00068 unload ();
00069 ASSERT (! m_library);
00070
00071 while (! m_infos.empty ())
00072 delete *m_infos.begin ();
00073
00074 delete m_cache;
00075 }
00076
00078 IgPluginManager *
00079 IgModule::manager (void) const
00080 { return m_manager; }
00081
00082 const lat::Filename &
00083 IgModule::libraryName (void) const
00084 { return m_libraryName; }
00085
00087 bool
00088 IgModule::bad (void) const
00089 { return m_bad; }
00090
00093 void
00094 IgModule::bad (bool value)
00095 { if ((m_bad = value)) clearCache (); }
00096
00097 lat::SharedLibrary *
00098 IgModule::library (void) const
00099 {
00100
00101 if (m_libraryName.empty ())
00102 return 0;
00103
00104 if (! m_library)
00105 {
00106 LOG (0, trace, LFplugin_manager,
00107 "loading shared library `" << m_libraryName << "'\n");
00108
00109 try
00110 {
00111 m_manager->feedback (IgPluginManager::StatusLoading, m_libraryName);
00112
00113 m_library = lat::SharedLibrary::load ((const std::string &) m_libraryName);
00114 }
00115 catch (lat::Error &e)
00116 {
00117 m_manager->feedback (IgPluginManager::ErrorLoadFailure, m_libraryName, &e);
00118 throw IgPluginError (e.clone ());
00119 }
00120 }
00121
00122 ASSERT (m_library);
00123 return m_library;
00124 }
00125
00126 bool
00127 IgModule::loaded (void) const
00128 { return m_libraryName.empty () || m_library;}
00129
00130 void
00131 IgModule::load (void)
00132 {
00133 if (m_libraryName.empty ())
00134 return;
00135
00136 LOG (0, trace, LFplugin_manager, "loading `" << m_libraryName << "'\n");
00137
00138 VERIFY (library ());
00139 VERIFY (checkEntryPoints ());
00140 }
00141
00142 void
00143 IgModule::unload (void)
00144 {
00145 if (m_libraryName.empty ())
00146 return;
00147
00148 detach ();
00149
00150
00151
00152
00153
00154
00155 if (m_library)
00156 {
00157 LOG (0, trace, LFplugin_manager, "unloading `" << m_libraryName << "'\n");
00158
00159 if (lat::ShellEnvironment ().has ("IGUANA_RELEASE_MODULES"))
00160 {
00161 m_manager->feedback (IgPluginManager::StatusUnloading, m_libraryName);
00162 m_library->release ();
00163 }
00164 else
00165 m_library->abandon ();
00166
00167 m_library = 0;
00168 }
00169 }
00170
00172 void
00173 IgModule::makeCache (void)
00174 {
00175 char time [40];
00176 const char *bad = m_bad ? "bad" : "good";
00177 sprintf (time, "%lu", (unsigned long) m_time);
00178
00179
00180 m_cache = new IgModuleDescriptor (0, s_tag,
00181 m_libraryName.nondirectory ().name (),
00182 time, bad);
00183 }
00184
00185 void
00186 IgModule::clearCache (void)
00187 { delete m_cache; makeCache (); }
00188
00189 IgModuleDescriptor *
00190 IgModule::cacheRoot (void) const
00191 { return m_cache; }
00192
00194 IgModule::InfoIterator
00195 IgModule::beginInfos (void) const
00196 { return m_infos.begin (); }
00197
00198 IgModule::InfoIterator
00199 IgModule::endInfos (void) const
00200 { return m_infos.end (); }
00201
00202 void
00203 IgModule::addInfo (IgPluginInfo *info, bool needCache)
00204 {
00205 if (needCache)
00206
00207 info->cache (cacheRoot ());
00208
00209 m_infos.push_back (info);
00210 m_manager->addInfo (info);
00211 }
00212
00213 void
00214 IgModule::detachInfo (IgPluginInfo *info)
00215 {
00216
00217
00218
00219 InfoList::iterator pos = std::find (m_infos.begin (), m_infos.end (), info);
00220 ASSERT (pos != m_infos.end ());
00221 m_infos.erase (pos);
00222 m_manager->removeInfo (info);
00223 }
00224
00226 void
00227 IgModule::restore (IgModuleDescriptor *from)
00228 {
00229
00230
00231
00232 from->dup (m_cache);
00233 m_manager->restore (this, from);
00234 }
00235
00237 void
00238 IgModule::cache (IgModuleDescriptor *to) const
00239 {
00240
00241
00242 m_cache->dup (to);
00243 }
00244
00246 bool
00247 IgModule::checkEntryPoints (void) const
00248 {
00249
00250
00251
00252
00253
00254 m_manager->feedback (IgPluginManager::StatusEntries, m_libraryName);
00255
00256 try
00257 {
00258 if (library ()->function (s_capEntryPoint))
00259 return true;
00260 }
00261 catch (lat::Error &)
00262 {
00263 }
00264
00265 try
00266 {
00267 return library ()->function (s_modEntryPoint);
00268 }
00269 catch (lat::Error &e)
00270 {
00271 m_manager->feedback (IgPluginManager::ErrorEntryFailure, m_libraryName, &e);
00272 throw IgPluginError (e.clone ());
00273 }
00274 }
00275
00276 IgModuleEntry
00277 IgModule::moduleEntryPoint (void)
00278 {
00279 lat::SharedLibrary::Function entry = 0;
00280
00281 if (! libraryName ().empty ())
00282 {
00283
00284 try { entry = library ()->function (s_modEntryPoint); }
00285 catch (lat::Error &) {}
00286
00287 LOG (0, trace, LFplugin_manager, "module entry point ("
00288 << s_modEntryPoint << ") = " << (void *) entry << '\n');
00289 }
00290
00291 return reinterpret_cast<IgModuleEntry> (entry);
00292 }
00293
00294 IgModuleCapEntry
00295 IgModule::capabilityEntryPoint (void)
00296 {
00297 lat::SharedLibrary::Function entry = 0;
00298
00299 if (! libraryName ().empty ())
00300 {
00301
00302 try { entry = library ()->function (s_capEntryPoint); }
00303 catch (lat::Error &) {}
00304
00305 LOG (0, trace, LFplugin_manager, "capability entry point ("
00306 << s_capEntryPoint << ") = " << (void *) entry << '\n');
00307 }
00308
00309 return reinterpret_cast<IgModuleCapEntry> (entry);
00310 }
00311
00312 void
00313 IgModule::attach (void)
00314 {
00315 if (! m_attached && ! libraryName ().empty ())
00316 {
00317 ASSERT (! m_definition);
00318
00319 LOG (0, trace, LFplugin_manager,
00320 "attaching module " << libraryName () << '\n' << lat::indent);
00321
00322
00323
00324 if (IgModuleEntry entry = moduleEntryPoint ())
00325 {
00326 m_definition = (*entry) ();
00327 ASSERT (m_definition);
00328
00329 m_manager->feedback (IgPluginManager::StatusAttaching, m_libraryName);
00330 m_definition->bind (this);
00331 m_definition->attach ();
00332 }
00333
00334 m_attached = true;
00335 LOG (0, trace, LFplugin_manager, lat::undent);
00336 }
00337 }
00338
00339 void
00340 IgModule::detach (void)
00341 {
00342 if (loaded () && m_attached && ! libraryName ().empty ())
00343 {
00344 LOG (0, trace, LFplugin_manager,
00345 "detaching module " << libraryName () << '\n' << lat::indent);
00346
00347 m_manager->feedback (IgPluginManager::StatusDetaching, m_libraryName);
00348 for (InfoIterator i = m_infos.begin (); i != m_infos.end (); ++i)
00349 (*i)->detach ();
00350
00351
00352 if (m_definition)
00353 {
00354 m_definition->detach ();
00355 m_definition->release ();
00356 m_definition = 0;
00357 }
00358 LOG (0, trace, LFplugin_manager, lat::undent);
00359 }
00360 }
00361
00362 void
00363 IgModule::query (void)
00364 {
00365 if (! libraryName ().empty ())
00366 {
00367 ASSERT (! m_definition);
00368
00369 LOG (0, trace, LFplugin_manager,
00370 "querying module " << libraryName () << '\n' << lat::indent);
00371
00372
00373
00374 clearCache ();
00375 while (! m_infos.empty ())
00376 delete *m_infos.begin ();
00377
00378
00379 if (IgModuleEntry entry = moduleEntryPoint ())
00380 {
00381 m_definition = (*entry) ();
00382 ASSERT (m_definition);
00383
00384 m_manager->feedback (IgPluginManager::StatusQuerying, m_libraryName);
00385 m_definition->bind (this);
00386 m_definition->query ();
00387 m_definition->release ();
00388 m_definition = 0;
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 if (IgModuleCapEntry capEntry = capabilityEntryPoint ())
00403 {
00404 IgModuleDef *def = new IgModuleDef;
00405 const char **names = 0;
00406 int n = -1;
00407
00408 (*capEntry) (names, n);
00409
00410 def->bind (this);
00411 for (int i = 0; names && names [i] && (n < 0 || i < n); ++i)
00412 IgPluginCapabilities::get ()->declare (def, names [i]);
00413 def->release ();
00414 delete def;
00415 }
00416
00417 LOG (0, trace, LFplugin_manager, lat::undent);
00418 }
00419 }
00420
00421 bool
00422 IgModule::attached (void)
00423 { return m_attached; }