00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #define OCL_STATIC
00030 #include "ocl/ComponentLoader.hpp"
00031 #include "ComponentLoader.hpp"
00032 #include <rtt/TaskContext.hpp>
00033 #include <rtt/Logger.hpp>
00034 #include <boost/filesystem.hpp>
00035
00036 #ifdef _WIN32
00037 #include <rtt/os/win32/dlfcn.h>
00038 #else
00039 #include <dlfcn.h>
00040 #endif
00041
00042 using namespace RTT;
00043 using namespace std;
00044 using namespace boost::filesystem;
00045
00046 namespace OCL
00047 {
00048 FactoryMap* ComponentFactories::Factories = 0;
00049 }
00050
00051 using namespace OCL;
00052
00053
00054 #ifdef __APPLE__
00055 static const std::string SO_EXT(".dylib");
00056 #else
00057 # ifdef _WIN32
00058 static const std::string SO_EXT(".dll");
00059 # else
00060 static const std::string SO_EXT(".so");
00061 # endif
00062 #endif
00063
00064
00065 # ifdef _WIN32
00066 static const std::string delimiters(";");
00067 static const std::string default_delimiter(";");
00068 # else
00069 static const std::string delimiters(":;");
00070 static const std::string default_delimiter(":");
00071 # endif
00072
00073 namespace OCL {
00074 namespace deployment {
00075
00076 boost::shared_ptr<ComponentLoader> ComponentLoader::minstance;
00077 static boost::shared_ptr<ComponentLoader> minstance2;
00078
00079
00080 vector<string> splitPaths(string const& str)
00081 {
00082 vector<string> paths;
00083
00084
00085 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
00086
00087 string::size_type pos = str.find_first_of(delimiters, lastPos);
00088
00089 while (string::npos != pos || string::npos != lastPos)
00090 {
00091
00092 if ( !str.substr(lastPos, pos - lastPos).empty() )
00093 paths.push_back(str.substr(lastPos, pos - lastPos));
00094
00095 lastPos = str.find_first_not_of(delimiters, pos);
00096
00097 pos = str.find_first_of(delimiters, lastPos);
00098 }
00099 if ( paths.empty() )
00100 paths.push_back(".");
00101 return paths;
00102 }
00103
00110 string makeShortFilename(string const& str) {
00111 string ret = str;
00112 if (str.substr(0,3) == "lib")
00113 ret = str.substr(3);
00114 if (ret.rfind(SO_EXT) != string::npos)
00115 ret = ret.substr(0, ret.rfind(SO_EXT) );
00116 return ret;
00117 }
00118
00119 boost::shared_ptr<ComponentLoader> ComponentLoader::Instance() {
00120 if (!minstance2)
00121 minstance2.reset( new ComponentLoader() );
00122 return minstance2;
00123 }
00124
00125 void ComponentLoader::Release() {
00126 minstance2.reset();
00127 }
00128
00129 void ComponentLoader::import( std::string const& package )
00130 {
00131
00132 vector<string> paths = splitPaths("." + default_delimiter + component_path);
00133
00134
00135 path subdir;
00136 if (package.empty() ) {
00137
00138 subdir = path(".");
00139 paths = splitPaths( component_path );
00140 } else {
00141 subdir = package;
00142 }
00143
00144
00145 path pdir = package;
00146 if ( pdir.is_complete() ) {
00147 component_path += default_delimiter + package;
00148
00149 paths = splitPaths(package);
00150 subdir = path(".");
00151 }
00152
00153 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00154 {
00155
00156 path p = path(*it) / subdir;
00157 if (is_directory(p))
00158 {
00159 log(Info) << "Importing component libraries from directory " << p.string() << " ..."<<endlog();
00160 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
00161 {
00162 log(Debug) << "Scanning file " << itr->path().string() << " ...";
00163 if (is_regular_file(itr->status()) && itr->path().extension() == SO_EXT )
00164 loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename() ), true);
00165 else {
00166 if (!is_regular_file(itr->status()))
00167 log(Debug) << "not a regular file: ignored."<<endlog();
00168 else
00169 log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
00170 }
00171 }
00172 }
00173 else
00174 log(Debug) << "No such directory: " << p << endlog();
00175
00176
00177 p = path(*it) / OROCOS_TARGET_NAME / subdir;
00178 if (is_directory(p))
00179 {
00180 log(Info) << "Importing component libraries from directory " << p.string() << " ..."<<endlog();
00181 for (directory_iterator itr(p); itr != directory_iterator(); ++itr)
00182 {
00183 log(Debug) << "Scanning file " << itr->path().string() << " ...";
00184 if (is_regular_file(itr->status()) && itr->path().extension() == SO_EXT )
00185 loadInProcess( itr->path().string(), makeShortFilename(itr->path().filename() ), true);
00186 else {
00187 if (!is_regular_file(itr->status()))
00188 log(Debug) << "not a regular file: ignored."<<endlog();
00189 else
00190 log(Debug) << "not a " + SO_EXT + " library: ignored."<<endlog();
00191 }
00192 }
00193 }
00194 else
00195 log(Debug) << "No such directory: " << p << endlog();
00196 }
00197 }
00198
00199 bool ComponentLoader::import( std::string const& package, std::string const& path_list )
00200 {
00201 vector<string> paths = splitPaths(path_list + default_delimiter + component_path);
00202 vector<string> tryouts( paths.size() * 4 );
00203 tryouts.clear();
00204
00205
00206 path arg( package );
00207 if (is_regular_file(arg)) {
00208 return loadInProcess(arg.string(), makeShortFilename( arg.filename() ), true);
00209 }
00210
00211 if ( isImported(package) ) {
00212 log(Info) <<"Component package '"<< package <<"' already imported." <<endlog();
00213 return true;
00214 } else {
00215 log(Info) << "Component package '"<< package <<"' not seen before." <<endlog();
00216 }
00217
00218 path dir = arg.parent_path();
00219 string file = arg.filename();
00220
00221 for (vector<string>::iterator it = paths.begin(); it != paths.end(); ++it)
00222 {
00223 path p = path(*it) / dir / (file + SO_EXT);
00224 tryouts.push_back( p.string() );
00225 if (is_regular_file( p ) && loadInProcess( p.string(), package, true ) )
00226 return true;
00227 p = path(*it) / dir / ("lib" + file + SO_EXT);
00228 tryouts.push_back( p.string() );
00229 if (is_regular_file( p ) && loadInProcess( p.string(), package, true ) )
00230 return true;
00231 p = path(*it) / OROCOS_TARGET_NAME / dir / (file + SO_EXT);
00232 tryouts.push_back( p.string() );
00233 if (is_regular_file( p ) && loadInProcess( p.string(), package, true ) )
00234 return true;
00235 p = path(*it) / OROCOS_TARGET_NAME / dir /("lib" + file + SO_EXT);
00236 tryouts.push_back( p.string() );
00237 if (is_regular_file( p ) && loadInProcess( p.string(), package, true ) )
00238 return true;
00239 }
00240 log(Error) << "No such package found in path: " << package << ". Tried:"<< endlog();
00241 for(vector<string>::iterator it=tryouts.begin(); it != tryouts.end(); ++it)
00242 log(Error) << *it << " ";
00243 log(Error)<< endlog();
00244 return false;
00245 }
00246
00247 bool ComponentLoader::isImported(string type_name)
00248 {
00249 return ComponentFactories::Instance().find(type_name) != ComponentFactories::Instance().end();
00250 }
00251
00252
00253 bool ComponentLoader::loadInProcess(string file, string libname, bool log_error) {
00254 path p(file);
00255 char* error;
00256 void* handle;
00257
00258
00259
00260
00261
00262 std::vector<LoadedLib>::iterator lib = loadedLibs.begin();
00263 while (lib != loadedLibs.end()) {
00264
00265 if ( lib->shortname == libname) {
00266 log(Warning) <<"Library "<< lib->filename <<" already loaded... " ;
00267
00268 bool can_unload = true;
00269 CompList::iterator cit;
00270 for( std::vector<std::string>::iterator ctype = lib->components_type.begin(); ctype != lib->components_type.end() && can_unload; ++ctype) {
00271 for ( cit = comps.begin(); cit != comps.end(); ++cit) {
00272 if( (*ctype) == cit->second.type ) {
00273
00274 log(Warning) << "can NOT reload library because of the instance " << cit->second.type <<"::"<<cit->second.instance->getName() <<endlog();
00275 can_unload = false;
00276 }
00277 }
00278 }
00279 if( can_unload ) {
00280 log(Warning) << "try to RELOAD"<<endlog();
00281 dlclose(lib->handle);
00282
00283 std::vector<LoadedLib>::iterator lib_un = lib;
00284 loadedLibs.erase(lib_un);
00285 lib = loadedLibs.end();
00286 }
00287 else
00288 return false;
00289 }
00290 else lib++;
00291 }
00292
00293 handle = dlopen ( p.string().c_str(), RTLD_NOW | RTLD_GLOBAL );
00294
00295 if (!handle) {
00296 if ( log_error ) {
00297 log(Error) << "Could not load library '"<< p.string() <<"':"<<endlog();
00298 log(Error) << dlerror() << endlog();
00299 }
00300 return false;
00301 }
00302
00303
00304 log(Debug)<<"Succesfully loaded "<<libname<<endlog();
00305 LoadedLib loading_lib(file, libname, handle);
00306 dlerror();
00307
00308
00309 FactoryMap* (*getfactory)(void) = 0;
00310 vector<string> (*getcomponenttypes)(void) = 0;
00311 FactoryMap* fmap = 0;
00312 getfactory = (FactoryMap*(*)(void))( dlsym(handle, "getComponentFactoryMap") );
00313 if ((error = dlerror()) == NULL) {
00314
00315 fmap = (*getfactory)();
00316 ComponentFactories::Instance().insert( fmap->begin(), fmap->end() );
00317 log(Info) << "Loaded multi component library '"<< file <<"'"<<endlog();
00318 getcomponenttypes = (vector<string>(*)(void))(dlsym(handle, "getComponentTypeNames"));
00319 if ((error = dlerror()) == NULL) {
00320 log(Debug) << "Components:";
00321 vector<string> ctypes = getcomponenttypes();
00322 for (vector<string>::iterator it = ctypes.begin(); it != ctypes.end(); ++it)
00323 log(Debug) <<" "<< *it;
00324 log(Debug) << endlog();
00325 }
00326 loadedLibs.push_back(loading_lib);
00327 return true;
00328 }
00329
00330
00331 dlerror();
00332
00333 RTT::TaskContext* (*factory)(std::string) = 0;
00334 std::string(*tname)(void) = 0;
00335 factory = (RTT::TaskContext*(*)(std::string))(dlsym(handle, "createComponent") );
00336 string create_error;
00337 error = dlerror();
00338 if (error) create_error = error;
00339 tname = (std::string(*)(void))(dlsym(handle, "getComponentType") );
00340 string gettype_error;
00341 error = dlerror();
00342 if (error) gettype_error = error;
00343 if ( factory && tname ) {
00344 std::string cname = (*tname)();
00345 if ( ComponentFactories::Instance().count(cname) == 1 ) {
00346 log(Warning) << "Component type name "<<cname<<" already used: overriding."<<endlog();
00347 }
00348 ComponentFactories::Instance()[cname] = factory;
00349 log(Info) << "Loaded component type '"<< cname <<"'"<<endlog();
00350 loading_lib.components_type.push_back( cname );
00351 loadedLibs.push_back(loading_lib);
00352 return true;
00353 }
00354
00355 log(Info) <<"Loaded regular library "<< loading_lib.filename <<"." <<endlog();
00356 log(Info) <<"NOTE: loading regular libraries is unavailable in RTT 2.x." <<endlog();
00357 return true;
00358 }
00359
00360 std::vector<std::string> ComponentLoader::listComponentTypes() const {
00361 vector<string> names;
00362 OCL::FactoryMap::iterator it;
00363 for( it = OCL::ComponentFactories::Instance().begin(); it != OCL::ComponentFactories::Instance().end(); ++it) {
00364 names.push_back( it->first );
00365 }
00366 return names;
00367 }
00368
00369 std::string ComponentLoader::getComponentPath() const {
00370 return component_path;
00371 }
00372
00373 void ComponentLoader::setComponentPath( std::string const& newpath ) {
00374 component_path = newpath;
00375 }
00376
00377
00378 RTT::TaskContext *ComponentLoader::loadComponent(const std::string & name, const std::string & type)
00379 {
00380 TaskContext* instance = 0;
00381 RTT::TaskContext* (*factory)(std::string name) = 0;
00382 log(Debug) << "Trying to create component "<< name <<" of type "<< type << endlog();
00383
00384
00385 if ( ComponentFactories::Instance().count(type) == 1 ) {
00386 factory = ComponentFactories::Instance()[ type ];
00387 if (factory == 0 ) {
00388 log(Error) <<"Found empty factory for Component type "<<type<<endlog();
00389 return 0;
00390 }
00391 }
00392
00393 if ( factory ) {
00394 log(Debug) <<"Found factory for Component type "<<type<<endlog();
00395 } else {
00396 log(Error) << "Unable to create Orocos Component '"<<type<<"': unknown component type." <<endlog();
00397 return 0;
00398 }
00399
00400 comps[name].type = type;
00401
00402 try {
00403 comps[name].instance = instance = (*factory)(name);
00404 } catch(...) {
00405 log(Error) <<"The constructor of component type "<<type<<" threw an exception!"<<endlog();
00406 }
00407
00408 if ( instance == 0 ) {
00409 log(Error) <<"Failed to load component with name "<<name<<": refused to be created."<<endlog();
00410 }
00411 return instance;
00412 }
00413
00414 bool ComponentLoader::unloadComponent( RTT::TaskContext* tc ) {
00415 if (!tc)
00416 return false;
00417 CompList::iterator it;
00418 it = comps.find( tc->getName() );
00419
00420 if ( it != comps.end() ) {
00421 delete tc;
00422 comps.erase(it);
00423 return true;
00424 }
00425 log(Error) <<"Refusing to unload a component I didn't load myself."<<endlog();
00426 return false;
00427 }
00428
00429 std::vector<std::string> ComponentLoader::listComponents() const
00430 {
00431 vector<string> names( comps.size() );
00432 for(map<string,ComponentData>::const_iterator it = comps.begin(); it != comps.end(); ++it)
00433 names.push_back( it->first );
00434 return names;
00435 }
00436
00437 }
00438 }