Back to index

nordugrid-arc-nox  1.1.0~rc6
Plugin.cpp
Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include <config.h>
00003 #endif
00004 
00005 #include <glibmm.h>
00006 
00007 #include <arc/Logger.h>
00008 #include <arc/StringConv.h>
00009 
00010 #include "Plugin.h"
00011 
00012 namespace Arc {
00013 
00014   static std::string strip_newline(const std::string& str) {
00015     std::string s(str);
00016     std::string::size_type p = 0;
00017     while((p=s.find('\r',p)) != std::string::npos) s[p]=' ';
00018     p=0;
00019     while((p=s.find('\n',p)) != std::string::npos) s[p]=' ';
00020     return s;
00021   }
00022 
00023   static PluginDescriptor* find_constructor(PluginDescriptor* desc,const std::string& kind,int min_version,int max_version) {
00024     if(!desc) return NULL;
00025     for(;(desc->kind) && (desc->name);++desc) {
00026       if((kind == desc->kind) || (kind.empty())) {
00027         if((min_version <= desc->version) && (max_version >= desc->version)) {
00028           if(desc->instance) return desc;
00029         };
00030       };
00031     };
00032     return NULL;
00033   }
00034 
00035   static PluginDescriptor* find_constructor(PluginDescriptor* desc,const std::string& kind,const std::string& name,int min_version,int max_version) {
00036     if(!desc) return NULL;
00037     for(;(desc->kind) && (desc->name);++desc) {
00038       if(((kind == desc->kind) || (kind.empty())) &&
00039          ((name == desc->name) || (name.empty()))) {
00040         if((min_version <= desc->version) && (max_version >= desc->version)) {
00041           if(desc->instance) return desc;
00042         };
00043       };
00044     };
00045     return NULL;
00046   }
00047 
00048   class ARCModuleDescriptor {
00049    private:
00050     bool valid;
00051     class ARCPluginDescriptor {
00052      public:
00053       std::string name;
00054       std::string kind;
00055       uint32_t version;
00056       bool valid;
00057       ARCPluginDescriptor(std::ifstream& in):valid(false) {
00058         if(!in) return;
00059         std::string line;
00060         // Protect against insane line length?
00061         while(std::getline(in,line)) {
00062           line = trim(line);
00063           if(line.empty()) break; // end of descripton
00064           std::string::size_type p = line.find('=');
00065           std::string tag = line.substr(0,p);
00066           line.replace(0,p+1,"");
00067           line = trim(line);
00068           if(line.length() < 2) return;
00069           if(line[0] != '"') return;
00070           if(line[line.length()-1] != '"') return;
00071           line=line.substr(1,line.length()-2);
00072           p=0;
00073           while((p = line.find('\\',p)) != std::string::npos) {
00074             line.replace(p,1,""); ++p;
00075           }
00076           if(tag == "name") {
00077             name = line;
00078           } else if(tag == "kind") {
00079             kind = line;
00080           } else if(tag == "version") {
00081             if(!stringto(line,version)) return;
00082           }
00083         }
00084         if(name.empty()) return;
00085         if(kind.empty()) return;
00086         valid = true;
00087       };
00088     };
00089     std::list<ARCPluginDescriptor> descriptors;
00090    public:
00091     ARCModuleDescriptor(std::ifstream& in):valid(false) {
00092       if(!in) return;
00093       for(;;) {
00094         ARCPluginDescriptor plg(in);
00095         if(!plg.valid) break;
00096         descriptors.push_back(plg);
00097       };
00098       valid = true;
00099     }
00100 
00101     operator bool(void) const { return valid; };
00102     bool operator!(void) const { return !valid; };
00103 
00104     bool contains(const std::list<std::string>& kinds) const {
00105       if(kinds.size() == 0) return valid;
00106       for(std::list<std::string>::const_iterator kind = kinds.begin();
00107                kind != kinds.end(); ++kind) {
00108         if(contains(*kind)) return true;
00109       };
00110       return false;
00111     }
00112 
00113     bool contains(const std::string& kind) const {
00114       for(std::list<ARCPluginDescriptor>::const_iterator desc =
00115                 descriptors.begin(); desc != descriptors.end(); ++desc) {
00116         if(desc->kind == kind) return true;
00117       };
00118       return false;
00119     };
00120 
00121     bool contains(const std::string& kind, const std::string& pname) {
00122       for(std::list<ARCPluginDescriptor>::const_iterator desc =
00123                 descriptors.begin(); desc != descriptors.end(); ++desc) {
00124         if((desc->name == pname) && (desc->kind == kind)) return true;
00125       };
00126       return false;
00127     };
00128 
00129     void get(std::list<PluginDesc>& descs) {
00130       for(std::list<ARCPluginDescriptor>::const_iterator desc =
00131                 descriptors.begin(); desc != descriptors.end(); ++desc) {
00132         PluginDesc pd;
00133         pd.name = desc->name;
00134         pd.kind = desc->kind;
00135         pd.version = desc->version;
00136         descs.push_back(pd);
00137       };
00138     };
00139   };
00140 
00141   static void replace_file_suffix(std::string& path,const std::string& suffix) {
00142     std::string::size_type name_p = path.rfind(G_DIR_SEPARATOR_S);
00143     if(name_p == std::string::npos) {
00144       name_p = 0;
00145     } else {
00146       ++name_p;
00147     }
00148     std::string::size_type suffix_p = path.find('.',name_p);
00149     if(suffix_p != std::string::npos) {
00150       path.resize(suffix_p);
00151     }
00152     path += "." + suffix;
00153   }
00154 
00155 
00156   static ARCModuleDescriptor* probe_descriptor(std::string name,ModuleManager& manager) {
00157     std::string::size_type p = 0;
00158     for(;;) {
00159       p=name.find(':',p);
00160       if(p == std::string::npos) break;
00161       name.replace(p,1,"_");
00162       ++p;
00163     };
00164     std::string path = manager.find(name);
00165     if(path.empty()) return NULL;
00166     replace_file_suffix(path,"apd");
00167     std::ifstream in(path.c_str());
00168     ARCModuleDescriptor* md = new ARCModuleDescriptor(in);
00169     if(!(*md)) {
00170       delete md;
00171       return NULL;
00172     };
00173     return md;
00174   }
00175 
00176 
00177   static Glib::Module* probe_module(std::string name,ModuleManager& manager) {
00178     std::string::size_type p = 0;
00179     for(;;) {
00180       p=name.find(':',p);
00181       if(p == std::string::npos) break;
00182       name.replace(p,1,"_");
00183       ++p;
00184     };
00185     return manager.load(name,true);
00186   }
00187 
00188   inline static Glib::Module* reload_module(Glib::Module* module,ModuleManager& manager) {
00189     if(!module) return NULL;
00190     return manager.reload(module);
00191   }
00192 
00193   inline static void unload_module(Glib::Module* module,ModuleManager& manager) {
00194     if(!module) return;
00195     manager.unload(module);
00196   }
00197 
00198   const char* plugins_table_name = PLUGINS_TABLE_SYMB;
00199 
00200   Logger PluginsFactory::logger(Logger::rootLogger, "Plugin");
00201 
00202   Plugin::Plugin(void) { }
00203 
00204   Plugin::~Plugin(void) { }
00205 
00206   Plugin* PluginsFactory::get_instance(const std::string& kind,PluginArgument* arg,bool search) {
00207     return get_instance(kind,0,INT_MAX,arg,search);
00208   }
00209 
00210   Plugin* PluginsFactory::get_instance(const std::string& kind,int version,PluginArgument* arg,bool search) {
00211     return get_instance(kind,version,version,arg,search);
00212   }
00213 
00214   Plugin* PluginsFactory::get_instance(const std::string& kind,int min_version,int max_version,PluginArgument* arg,bool search) {
00215     if(arg) arg->set_factory(this);
00216     Glib::Mutex::Lock lock(lock_);
00217     descriptors_t_::iterator i = descriptors_.begin();
00218     for(;i != descriptors_.end();++i) {
00219       PluginDescriptor* desc = i->second;
00220       for(;;) {
00221         desc=find_constructor(desc,kind,min_version,max_version);
00222         if(!desc) break;
00223         if(arg) {
00224           modules_t_::iterator m = modules_.find(i->first);
00225           if(m != modules_.end()) {
00226             arg->set_module(m->second);
00227           } else {
00228             arg->set_module(NULL);
00229           };
00230         };
00231         lock.release();
00232         Plugin* plugin = desc->instance(arg);
00233         if(plugin) return plugin;
00234         lock.acquire();
00235         ++desc;
00236       };
00237     };
00238     if(!search) return NULL;
00239     // Try to load module of plugin
00240     std::string mname = kind;
00241     ARCModuleDescriptor* mdesc = probe_descriptor(mname,*this);
00242     if(mdesc) {
00243       if(!mdesc->contains(kind)) {
00244         delete mdesc;
00245         return NULL;
00246       };
00247       delete mdesc;
00248       mdesc = NULL;
00249     };
00250     // Descriptor not found or indicates presence of requested kinds.
00251     if(!try_load_) {
00252       logger.msg(ERROR, "Could not find loadable module descriptor by name %s",kind);
00253       return NULL;
00254     };
00255     // Now try to load module directly
00256     Glib::Module* module = probe_module(kind,*this);
00257     if (module == NULL) {
00258       logger.msg(ERROR, "Could not find loadable module by name %s (%s)",kind,strip_newline(Glib::Module::get_last_error()));
00259       return NULL;
00260     };
00261     // Identify table of descriptors
00262     void *ptr = NULL;
00263     if(!module->get_symbol(plugins_table_name,ptr)) {
00264       logger.msg(VERBOSE, "Module %s is not an ARC plugin (%s)",kind,strip_newline(Glib::Module::get_last_error()));
00265       unload_module(module,*this);
00266       return NULL;
00267     };
00268     // Try to find plugin in new table
00269     PluginDescriptor* desc = (PluginDescriptor*)ptr;
00270     for(;;) {
00271       desc=find_constructor(desc,kind,min_version,max_version);
00272       if(!desc) break;
00273       if(arg) arg->set_module(module);
00274       lock.release();
00275       Plugin* plugin = desc->instance(arg);
00276       lock.acquire();
00277       if(plugin) {
00278         // Keep plugin loaded and registered
00279         Glib::Module* nmodule = reload_module(module,*this);
00280         if(!nmodule) {
00281           logger.msg(VERBOSE, "Module %s failed to reload (%s)",mname,strip_newline(Glib::Module::get_last_error()));
00282           unload_module(module,*this);
00283           return false;
00284         };
00285         descriptors_[mname]=(PluginDescriptor*)ptr;
00286         modules_[mname]=nmodule;
00287         //descriptors_.push_back((PluginDescriptor*)ptr);
00288         //modules_.push_back(module);
00289         return plugin;
00290       };
00291       ++desc;
00292     };
00293     unload_module(module,*this);
00294     return NULL;
00295   }
00296 
00297   Plugin* PluginsFactory::get_instance(const std::string& kind,const std::string& name,PluginArgument* arg,bool search) {
00298     return get_instance(kind,name,0,INT_MAX,arg,search);
00299   }
00300 
00301   Plugin* PluginsFactory::get_instance(const std::string& kind,const std::string& name,int version,PluginArgument* arg,bool search) {
00302     return get_instance(kind,version,version,arg,search);
00303   }
00304 
00305   Plugin* PluginsFactory::get_instance(const std::string& kind,const std::string& name,int min_version,int max_version,PluginArgument* arg,bool search) {
00306     if(arg) arg->set_factory(this);
00307     Glib::Mutex::Lock lock(lock_);
00308     descriptors_t_::iterator i = descriptors_.begin();
00309     for(;i != descriptors_.end();++i) {
00310       PluginDescriptor* desc = find_constructor(i->second,kind,name,min_version,max_version);
00311       if(arg) {
00312         modules_t_::iterator m = modules_.find(i->first);
00313         if(m != modules_.end()) {
00314           arg->set_module(m->second);
00315         } else {
00316           arg->set_module(NULL);
00317         };
00318       };
00319       if(desc) {
00320         lock.release();
00321         return desc->instance(arg);
00322       }
00323     };
00324     if(!search) return NULL;
00325     // Try to load module - first by name of plugin
00326     std::string mname = name;
00327     ARCModuleDescriptor* mdesc = probe_descriptor(mname,*this);
00328     if(mdesc) {
00329       if(!mdesc->contains(kind,name)) {
00330         delete mdesc;
00331         logger.msg(ERROR, "Loadable module %s contains no requested plugin %s of kind %s",mname,name,kind);
00332         return NULL;
00333       };
00334       delete mdesc;
00335       mdesc = NULL;
00336     };
00337     // Descriptor not found or indicates presence of requested kinds.
00338     // Now try to load module directly
00339     Glib::Module* module = try_load_?probe_module(name,*this):NULL;
00340     if (module == NULL) {
00341       // Then by kind of plugin
00342       mname=kind;
00343       mdesc = probe_descriptor(mname,*this);
00344       if(mdesc) {
00345         if(!mdesc->contains(kind,name)) {
00346           delete mdesc;
00347           logger.msg(ERROR, "Loadable module %s contains no requested plugin %s of kind %s",mname,name,kind);
00348           return NULL;
00349         };
00350         delete mdesc;
00351         mdesc = NULL;
00352       };
00353       if(!try_load_) {
00354         logger.msg(ERROR, "Could not find loadable module descriptor by names %s and %s",name,kind);
00355         return NULL;
00356       };
00357       // Descriptor not found or indicates presence of requested kinds.
00358       // Now try to load module directly
00359       module=probe_module(kind,*this);
00360       logger.msg(ERROR, "Could not find loadable module by names %s and %s (%s)",name,kind,strip_newline(Glib::Module::get_last_error()));
00361       return NULL;
00362     };
00363     // Identify table of descriptors
00364     void *ptr = NULL;
00365     if(!module->get_symbol(plugins_table_name,ptr)) {
00366       logger.msg(VERBOSE, "Module %s is not an ARC plugin (%s)",mname,strip_newline(Glib::Module::get_last_error()));
00367       unload_module(module,*this);
00368       return NULL;
00369     };
00370     // Try to find plugin in new table
00371     PluginDescriptor* desc = find_constructor((PluginDescriptor*)ptr,kind,name,min_version,max_version);
00372     if(desc) {
00373       // Keep plugin loaded and registered
00374       Glib::Module* nmodule = reload_module(module,*this);
00375       if(!nmodule) {
00376         logger.msg(VERBOSE, "Module %s failed to reload (%s)",mname,strip_newline(Glib::Module::get_last_error()));
00377         unload_module(module,*this);
00378         return false;
00379       };
00380       descriptors_[mname]=(PluginDescriptor*)ptr;
00381       modules_[mname]=nmodule;
00382       //descriptors_.push_back((PluginDescriptor*)ptr);
00383       //modules_.push_back(module);
00384       if(arg) arg->set_module(nmodule);
00385       lock.release();
00386       return desc->instance(arg);
00387     };
00388     unload_module(module,*this);
00389     return NULL;
00390   }
00391 
00392   bool PluginsFactory::load(const std::string& name) {
00393     std::list<std::string> kinds;
00394     return load(name,kinds);
00395   }
00396 
00397   bool PluginsFactory::load(const std::string& name,const std::string& kind) {
00398     std::list<std::string> kinds;
00399     kinds.push_back(kind);
00400     return load(name,kinds);
00401   }
00402 
00403   bool PluginsFactory::load(const std::string& name,const std::list<std::string>& kinds) {
00404     std::list<std::string> pnames;
00405     return load(name,kinds,pnames);
00406   }
00407 
00408   bool PluginsFactory::load(const std::string& name,const std::list<std::string>& kinds,const std::list<std::string>& pnames) {
00409     // In real use-case all combinations of kinds and pnames
00410     // have no sense. So normally if both are defined each contains
00411     // only onr item.
00412     if(name.empty()) return false;
00413     Glib::Module* module = NULL;
00414     PluginDescriptor* desc = NULL;
00415     void *ptr = NULL;
00416     std::string mname;
00417     Glib::Mutex::Lock lock(lock_);
00418     // Check if module already loaded
00419     descriptors_t_::iterator d = descriptors_.find(name);
00420     if(d != descriptors_.end()) {
00421       desc = d->second;
00422       if(!desc) return false;
00423     } else {
00424       // Try to load module by specified name
00425       mname = name;
00426       // First try to find descriptor of module
00427       ARCModuleDescriptor* mdesc = probe_descriptor(mname,*this);
00428       if(mdesc) {
00429         if(!mdesc->contains(kinds)) {
00430           //logger.msg(VERBOSE, "Module %s does not contain plugin(s) of specified kind(s)",mname);
00431           delete mdesc;
00432           return false;
00433         };
00434         delete mdesc;
00435         mdesc = NULL;
00436       };
00437       if(!try_load_) {
00438         logger.msg(ERROR, "Could not find loadable module descriptor by name %s",name);
00439         return NULL;
00440       };
00441       // Descriptor not found or indicates presence of requested kinds.
00442       // Descriptor not found or indicates presence of requested kinds.
00443       // Now try to load module directly
00444       module = probe_module(mname,*this);
00445       if (module == NULL) {
00446         logger.msg(ERROR, "Could not find loadable module by name %s (%s)",name,strip_newline(Glib::Module::get_last_error()));
00447         return false;
00448       };
00449       // Identify table of descriptors
00450       if(!module->get_symbol(plugins_table_name,ptr)) {
00451         logger.msg(VERBOSE, "Module %s is not an ARC plugin (%s)",mname,strip_newline(Glib::Module::get_last_error()));
00452         unload_module(module,*this);
00453         return false;
00454       };
00455       desc = (PluginDescriptor*)ptr;
00456     };
00457     if(kinds.size() > 0) {
00458       for(std::list<std::string>::const_iterator kind = kinds.begin();
00459           kind != kinds.end(); ++kind) {
00460         if(kind->empty()) continue;
00461         desc=find_constructor(desc,*kind,0,INT_MAX);
00462         if(desc) break;
00463       };
00464       if(!desc) {
00465         //logger.msg(VERBOSE, "Module %s does not contain plugin(s) of specified kind(s)",mname);
00466         if(module) unload_module(module,*this);
00467         return false;
00468       };
00469     };
00470     if(!mname.empty()) {
00471       Glib::Module* nmodule=reload_module(module,*this);
00472       if(!nmodule) {
00473         logger.msg(VERBOSE, "Module %s failed to reload (%s)",mname,strip_newline(Glib::Module::get_last_error()));
00474         unload_module(module,*this);
00475         return false;
00476       };
00477       descriptors_[mname]=(PluginDescriptor*)ptr;
00478       modules_[mname]=nmodule;
00479       //descriptors_.push_back((PluginDescriptor*)ptr);
00480       //modules_.push_back(module);
00481     };
00482     return true;
00483   }
00484 
00485   bool PluginsFactory::load(const std::list<std::string>& names,const std::string& kind) {
00486     std::list<std::string> kinds;
00487     kinds.push_back(kind);
00488     return load(names,kinds);
00489   }
00490 
00491   bool PluginsFactory::load(const std::list<std::string>& names,const std::string& kind,const std::string& pname) {
00492     bool r = false;
00493     std::list<std::string> kinds;
00494     std::list<std::string> pnames;
00495     kinds.push_back(kind);
00496     pnames.push_back(pname);
00497     for(std::list<std::string>::const_iterator name = names.begin();
00498                                 name != names.end();++name) {
00499       if(load(*name,kinds,pnames)) r=true;
00500     }
00501     return r;
00502   }
00503 
00504   bool PluginsFactory::load(const std::list<std::string>& names,const std::list<std::string>& kinds) {
00505     bool r = false;
00506     for(std::list<std::string>::const_iterator name = names.begin();
00507                                 name != names.end();++name) {
00508       if(load(*name,kinds)) r=true;
00509     }
00510     return r;
00511   }
00512 
00513   bool PluginsFactory::scan(const std::string& name, ModuleDesc& desc) {
00514     ARCModuleDescriptor* mod = probe_descriptor(name,*this);
00515     if(mod) {
00516       desc.name = name;
00517       mod->get(desc.plugins);
00518       return true;
00519     }
00520     // Descriptor not found
00521     if(!try_load_) return false;
00522     // Now try to load module directly
00523     Glib::Module* module = probe_module(name,*this);
00524     if (module == NULL) return false;
00525     // Identify table of descriptors
00526     void *ptr = NULL;
00527     if(!module->get_symbol(plugins_table_name,ptr)) {
00528       unload_module(module,*this);
00529       return false;
00530     };
00531     PluginDescriptor* d = (PluginDescriptor*)ptr;
00532     if(!d) {
00533       unload_module(module,*this);
00534       return false;
00535     };
00536     for(;(d->kind) && (d->name);++d) {
00537       PluginDesc pd;
00538       pd.name = d->name;
00539       pd.kind = d->kind;
00540       pd.version = d->version;
00541       desc.plugins.push_back(pd);
00542     };
00543     return true;
00544   }
00545 
00546   bool PluginsFactory::scan(const std::list<std::string>& names, std::list<ModuleDesc>& descs) {
00547     bool r = false;
00548     ModuleDesc desc;
00549     for(std::list<std::string>::const_iterator name = names.begin();
00550                                 name != names.end();++name) {
00551       if(scan(*name,desc)) {
00552         r=true;
00553         descs.push_back(desc);
00554       }
00555     }
00556     return r;
00557   }
00558 
00559   void PluginsFactory::report(std::list<ModuleDesc>& descs) {
00560     for(descriptors_t_::iterator ds = descriptors_.begin();
00561                ds != descriptors_.end(); ++ds) {
00562       PluginDescriptor* d = ds->second;
00563       if(!d) continue;
00564       ModuleDesc md;
00565       md.name = ds->first;
00566       for(;(d->kind) && (d->name);++d) {
00567         PluginDesc pd;
00568         pd.name = d->name;
00569         pd.kind = d->kind;
00570         pd.version = d->version;
00571         md.plugins.push_back(pd);
00572       };
00573       descs.push_back(md);
00574     }
00575   }
00576 
00577   PluginsFactory::PluginsFactory(XMLNode cfg): ModuleManager(cfg),
00578                                                try_load_(true) {
00579   }
00580 
00581   PluginArgument::PluginArgument(void): factory_(NULL), module_(NULL) {
00582   }
00583 
00584   PluginArgument::~PluginArgument(void) {
00585   }
00586 
00587   PluginsFactory* PluginArgument::get_factory(void) {
00588     return factory_;
00589   }
00590 
00591   Glib::Module* PluginArgument::get_module(void) {
00592     return module_;
00593   }
00594 
00595   void PluginArgument::set_factory(PluginsFactory* factory) {
00596     factory_=factory;
00597   }
00598 
00599   void PluginArgument::set_module(Glib::Module* module) {
00600     module_=module;
00601   }
00602 
00603 
00604 } // namespace Arc
00605