00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef _CJVISITORFACTORY_H_
00020 #define _CJVISITORFACTORY_H_ 1
00021
00022 #include <map>
00023 #include <vector>
00024 #include <iostream>
00025 #include <utility>
00026 #include <stdexcept>
00027
00028 #ifdef _WIN32
00029 #include <windows.h>
00030 #endif
00031
00032 #ifndef BUILD_STATIC_MITIE
00033 #ifdef _WIN32
00034
00035 extern __declspec(dllimport) int init();
00036 extern __declspec(dllimport) int func(int*);
00037 extern __declspec(dllimport) int fini();
00038 #else
00039 #include <dlfcn.h>
00040 #endif // not _WIN32
00041 #endif // BUILD_STATIC_MITIE
00042
00043
00044 #include <boost/shared_ptr.hpp>
00045 #include <boost/random.hpp>
00046 #define BOOST_FILESYSTEM_NO_DEPRECATED
00047 #include <boost/filesystem/operations.hpp>
00048 #include <boost/filesystem/path.hpp>
00049 #include "JLOG.hh"
00050
00051 namespace jmitie {
00052
00054 class Cj_NotFoundInFactoryException : public std::runtime_error {
00055 public:
00056 explicit Cj_NotFoundInFactoryException (const std::string & message) : std::runtime_error(message) {}
00057 virtual ~Cj_NotFoundInFactoryException() throw() {}
00058 };
00059
00061 class Cj_NameCollisionException : public std::runtime_error {
00062 public:
00063 explicit Cj_NameCollisionException (const std::string & message) : std::runtime_error(message) {}
00064 virtual ~Cj_NameCollisionException() throw() {}
00065 };
00066
00068 class Cj_SymbolMissingException : public std::runtime_error {
00069 public:
00070 explicit Cj_SymbolMissingException (const std::string & message) : std::runtime_error(message) {}
00071 virtual ~Cj_SymbolMissingException() throw() {}
00072 };
00073
00075 class Cj_DLLException : public std::runtime_error {
00076 public:
00077 explicit Cj_DLLException (const std::string & message) : std::runtime_error(message) {}
00078 virtual ~Cj_DLLException() throw() {}
00079 };
00080
00082 class Cj_FileSystemException : public std::runtime_error {
00083 public:
00084 explicit Cj_FileSystemException (const std::string & message) : std::runtime_error(message) {}
00085 virtual ~Cj_FileSystemException() throw() {}
00086 };
00087
00088 #ifdef _WIN32
00089 typedef HINSTANCE DLLHandle_t;
00090 #else
00091 typedef void * DLLHandle_t;
00092 #endif
00093
00101 template <class VisitorType_t> class CjVisitorFactoryEntry {
00102 public:
00104 typedef VisitorType_t VisitorType;
00106 typedef VisitorType * (* f_create_t)(const std::string & type_name, const std::string & args, const typename VisitorType::ctor_va_t & var_arg );
00108 typedef std::vector< std::string > (* f_getNames_t)();
00110 typedef void (* f_destroy_t)(VisitorType *);
00112 typedef std::string (* f_getProperty_t)(const std::string & type_name, const std::string & prop_name );
00113
00114 private:
00115 CjVisitorFactoryEntry(const CjVisitorFactoryEntry<VisitorType> &);
00116 DLLHandle_t m_h;
00117 std::string m_fname;
00118 f_create_t m_c;
00119 f_destroy_t m_d;
00120 f_getNames_t m_n;
00121 f_getProperty_t m_p;
00122
00123 public:
00125 std::string fname() const { return m_fname; }
00127 f_create_t c() const { return m_c; }
00129 f_destroy_t d() const { return m_d; }
00131 f_getNames_t n() const { return m_n; }
00133 f_getProperty_t p() const { return m_p; }
00134
00136
00142 CjVisitorFactoryEntry ( f_create_t c, f_destroy_t d, f_getNames_t n, f_getProperty_t p ):m_h(0),m_fname("static"),m_c(c),m_d(d),m_n(n),m_p(p) { }
00143
00144 #ifndef BUILD_STATIC_MITIE
00145 #ifdef _WIN32
00146
00147
00156 CjVisitorFactoryEntry (const char * fname, const char * create_name, const char * destroy_name, const char * getnames_name, const char * getproperty_name):m_h(0),m_fname(fname),m_c(0),m_d(0),m_n(0),m_p(0) {
00157 HINSTANCE lib_handle;
00158 JLOG(4, std::cout << "CjVisitorFactoryEntry<VisitorType_t>::CjVisitorFactoryEntry<VisitorType_t>(): Loading DLL: " << fname << std::endl; )
00159 JLOG(5, std::cout << "CjVisitorFactoryEntry<VisitorType_t>::CjVisitorFactoryEntry<VisitorType_t>(): Checking for functions " << create_name << ", " << destroy_name << " and " << getnames_name << "." << std::endl; )
00160 m_h = LoadLibrary(TEXT(fname.c_str()));
00161 if(!m_h) { throw Cj_DLLException(std::string("Error when loading library ") + fname ); }
00162 m_c = GetProcAddress(lib_handle, "init");
00163 m_c = (f_create_t) dlsym( m_h, create_name );
00164 dl_error = dlerror();
00165 if(dl_error) {
00166 dlclose(m_h);
00167 throw Cj_SymbolMissingException(std::string("Error when finding function ") + create_name + " in DLL " + fname + ": " + dl_error);
00168 }
00169 m_d = (f_destroy_t) dlsym( m_h, destroy_name );
00170 dl_error = dlerror();
00171 if(dl_error) {
00172 dlclose(m_h);
00173 throw Cj_SymbolMissingException(std::string("Error when finding function ") + destroy_name + " in DLL " + fname + ": " + dl_error);
00174 }
00175 m_n = (f_getNames_t) dlsym( m_h, getnames_name );
00176 dl_error = dlerror();
00177 if(dl_error) {
00178 dlclose(m_h);
00179 throw Cj_SymbolMissingException(std::string("Error when finding function ") + getnames_name + " in DLL " + fname + ": " + dl_error);
00180 }
00181 m_p = (f_getProperty_t) dlsym( m_h, getproperty_name );
00182 dl_error = dlerror();
00183 if(dl_error) {
00184 dlclose(m_h);
00185 throw Cj_SymbolMissingException(std::string("Error when finding function ") + getproperty_name + " in DLL " + fname + ": " + dl_error);
00186 }
00187 JLOG(4, std::cout << "CjVisitorFactoryEntry<VisitorType_t>::CjVisitorFactoryEntry<VisitorType_t>(): Loaded DLL: " << fname << std::endl; )
00188 }
00189 #else
00191
00200 CjVisitorFactoryEntry (const char * fname, const char * create_name, const char * destroy_name, const char * getnames_name, const char * getproperty_name):m_h(0),m_fname(fname),m_c(0),m_d(0),m_n(0),m_p(0) {
00201 char * dl_error = dlerror();
00202 JLOG(4, std::cout << "CjVisitorFactoryEntry<VisitorType_t>::CjVisitorFactoryEntry<VisitorType_t>(): Loading DLL: " << fname << std::endl; )
00203 JLOG(5, std::cout << "CjVisitorFactoryEntry<VisitorType_t>::CjVisitorFactoryEntry<VisitorType_t>(): Checking for functions " << create_name << ", " << destroy_name << " and " << getnames_name << "." << std::endl; )
00204 m_h = dlopen(fname, RTLD_NOW | RTLD_LOCAL);
00205 dl_error = dlerror();
00206 if(dl_error) { throw Cj_DLLException(std::string("Error when loading library ") + fname + ": " + dl_error); }
00207 if(!m_h) { throw Cj_DLLException(std::string("Error when loading library ") + fname + ": reason unkown."); }
00208 m_c = (f_create_t) dlsym( m_h, create_name );
00209 dl_error = dlerror();
00210 if(dl_error) {
00211 dlclose(m_h);
00212 throw Cj_SymbolMissingException(std::string("Error when finding function ") + create_name + " in DLL " + fname + ": " + dl_error);
00213 }
00214 m_d = (f_destroy_t) dlsym( m_h, destroy_name );
00215 dl_error = dlerror();
00216 if(dl_error) {
00217 dlclose(m_h);
00218 throw Cj_SymbolMissingException(std::string("Error when finding function ") + destroy_name + " in DLL " + fname + ": " + dl_error);
00219 }
00220 m_n = (f_getNames_t) dlsym( m_h, getnames_name );
00221 dl_error = dlerror();
00222 if(dl_error) {
00223 dlclose(m_h);
00224 throw Cj_SymbolMissingException(std::string("Error when finding function ") + getnames_name + " in DLL " + fname + ": " + dl_error);
00225 }
00226 m_p = (f_getProperty_t) dlsym( m_h, getproperty_name );
00227 dl_error = dlerror();
00228 if(dl_error) {
00229 dlclose(m_h);
00230 throw Cj_SymbolMissingException(std::string("Error when finding function ") + getproperty_name + " in DLL " + fname + ": " + dl_error);
00231 }
00232 JLOG(4, std::cout << "CjVisitorFactoryEntry<VisitorType_t>::CjVisitorFactoryEntry<VisitorType_t>(): Loaded DLL: " << fname << std::endl; )
00233 }
00234 #endif
00235 #endif
00237 ~CjVisitorFactoryEntry() {
00238 #ifndef BUILD_STATIC_MITIE
00239 JLOG(4, std::cout << "Closing DLL " << m_fname << std::endl; )
00240 if(m_h) dlclose(m_h);
00241 #endif // BUILD_STATIC_MITIE
00242 }
00243 };
00244
00245
00246
00256 template <typename FacEntryType > class CjVisitorFactory {
00257 public:
00259 typedef typename FacEntryType::f_create_t f_create_t;
00261 typedef typename FacEntryType::f_destroy_t f_destroy_t;
00263 typedef typename FacEntryType::f_getNames_t f_getNames_t;
00265 typedef typename FacEntryType::f_getProperty_t f_getProperty_t;
00267 typedef typename FacEntryType::VisitorType VisitorType;
00269 typedef boost::shared_ptr<VisitorType> Visitor_shared_ptr;
00271 typedef typename VisitorType::ctor_va_t VisitorArgumentType;
00272
00273 protected:
00275 typedef std::map< std::string, boost::shared_ptr< FacEntryType >, std::less<std::string> > factory_t;
00277 factory_t m_factory;
00279 std::string m_description;
00280
00281 private:
00282 CjVisitorFactory(const CjVisitorFactory &);
00283
00284 public:
00286 CjVisitorFactory(const char * desc):m_description(desc) {}
00288 std::string description() const { return m_description; }
00289
00291
00293 ~CjVisitorFactory() {
00294 JLOG(5, std::cout << "CjVisitorFactory::~CjVisitorFactory() called on factory \"" << m_description << "\"." << std::endl; )
00295 clear();
00296 }
00298
00300 void clear() {
00301 JLOG(5, std::cout << "CjVisitorFactory::clear() called on factory \"" << m_description << "\"." << std::endl; )
00302 m_factory.clear();
00303 }
00304
00306
00312 void registerStaticEntry ( f_create_t c, f_destroy_t d, f_getNames_t n, f_getProperty_t p ) {
00313 boost::shared_ptr<FacEntryType> fe (new FacEntryType ( c, d, n, p ));
00314 std::vector< std::string > obj_names ( (*n)() );
00315 JLOG(4, std::cout << "CjVisitorFactory::CjVisitorFactory: Adding static entries to factory.." << std::endl; )
00316 for(std::vector< std::string >::const_iterator i = obj_names.begin(); i != obj_names.end(); ++i ) {
00317 JLOG(5, std::cout << "CjVisitorFactory::CjVisitorFactory: Adding static " << *i << " to factory" << std::endl; )
00318 m_factory.insert( make_pair ( *i, fe ) );
00319 }
00320 }
00321
00322 #ifndef BUILD_STATIC_MITIE
00323
00325
00337 void loadAll( const char * create_name, const char * destroy_name, const char * getnames_name, const char * getproperty_name, const char * dir = NULL, const bool continueOnFail = false, const bool overwriteExisting = false) {
00338 namespace fs = boost::filesystem;
00339 typedef std::vector< std::string > filelist_t;
00340
00341
00342 #ifdef _WIN32
00343 std::string ext(".dll");
00344 #else
00345 std::string ext(".so");
00346 #endif
00347 filelist_t fnamelist;
00348
00349 fs::path full_path( (dir==NULL) ? fs::initial_path<fs::path>() : fs::system_complete( fs::path( dir ) ) );
00350
00351 if ( !fs::exists( full_path ) ) throw Cj_FileSystemException(std::string(full_path.file_string()) + " does not exist");
00352 if ( !fs::is_directory( full_path ) ) throw Cj_FileSystemException(std::string(dir) + " must be a directory");
00353
00354 fs::directory_iterator end_iter;
00355 for ( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr ) {
00356 try {
00357 if ( fs::is_regular_file( dir_itr->status() ) && (0 == ext.compare(dir_itr->path().extension()) ) ) {
00358 fnamelist.push_back( dir_itr->path().string() );
00359 }
00360 } catch ( const std::exception & ex ) {
00361 JLOG(2, std::cout << "Exception caught in CjVisitorFactory::loadAll:" << dir_itr->path().filename() << " " << ex.what() << std::endl; )
00362 std::cout << "Exception caught in CjVisitorFactory::loadAll when creating file list:" << dir_itr->path().filename() << " " << ex.what() << std::endl;
00363 throw Cj_FileSystemException("Exception in CjVisitorFactory::loadAll when checking " + dir_itr->path().filename() + " for file list: " + ex.what() );
00364 }
00365 }
00366
00367
00368 factory_t new_factory(m_factory);
00369
00370 for( filelist_t::const_iterator it = fnamelist.begin(); it != fnamelist.end(); ++it ) {
00371 factory_t loaded_factory;
00372 try {
00373 loaded_factory = loadOneDLLToFactoryCopy( it->c_str(), create_name, destroy_name, getnames_name, getproperty_name, continueOnFail, overwriteExisting, &new_factory );
00374 JLOG(4, std::cout << "loadOneDLLToNewFactory returned size delta of " << loaded_factory.size()-new_factory.size() << " when loading " << *it << std::endl; )
00375
00376 }
00377 catch(Cj_NameCollisionException & e) {
00378
00379 assert(!continueOnFail);
00380 throw;
00381 }
00382 catch(Cj_SymbolMissingException & e) {
00383 JLOG(4, std::cout << "Missing symbols when loading " << *it << ": \"" << e.what() << "\"" << std::endl; )
00384 continue;
00385 }
00386
00387 new_factory.swap(loaded_factory);
00388 }
00389 JLOG(4, std::cout << "CjVisitorFactory::loadAll: factory size delta is " << new_factory.size()-m_factory.size() << std::endl; )
00390 swap(m_factory, new_factory);
00391 }
00392
00394
00406 void loadOne(const char * fname, const char * create_name, const char * destroy_name, const char * getnames_name, const char * getproperty_name, bool continueOnDupe = false, const bool overwriteExisting = false ) {
00407 factory_t loaded_factory (loadOneDLLToFactoryCopy( fname, create_name, destroy_name, getnames_name, getproperty_name, continueOnDupe, overwriteExisting, &m_factory ) );
00408
00409
00410 std::swap(m_factory, loaded_factory);
00411 }
00412
00414
00428 static factory_t loadOneDLLToFactoryCopy( const char * fname, const char * create_name, const char * destroy_name, const char * getnames_name, const char * getproperty_name, const bool continueOnDupe, const bool overwriteExisting, const factory_t * old_factory = 0 ) {
00429 factory_t new_factory;
00430 if(old_factory) new_factory = *old_factory;
00431 boost::shared_ptr<FacEntryType> fe (new FacEntryType ( fname, create_name, destroy_name, getnames_name, getproperty_name ));
00432 std::vector< std::string > obj_names ((fe->n())());
00433
00434 for(std::vector< std::string >::const_iterator i = obj_names.begin(); i != obj_names.end(); ++i ) {
00435
00436 typename factory_t::iterator old (new_factory.find(*i));
00437 if(new_factory.end() != old) {
00438 if(!continueOnDupe) throw Cj_NameCollisionException( std::string("CjVisitorFactory::loadOneDLLToNewFactory( const char * fname, const factory_t * old_factory, const bool continueOnDupe, const bool overwriteExisting ): When attempting to load ") + fname + " found duplicate " + *i );
00439 if(overwriteExisting) new_factory.erase(old);
00440 else continue;
00441 }
00442 std::pair < typename factory_t::iterator , bool > ins (new_factory.insert( make_pair ( *i, fe ) ));
00443 assert(ins.second);
00444 }
00445 return new_factory;
00446 }
00447 #endif // BUILD_STATIC_MITIE
00448
00450
00457 Visitor_shared_ptr createInstance_sharedptr( const std::string & name, const std::string & args, const VisitorArgumentType & va ) const {
00458 JLOG(5, std::cout << "CjVisitorFactory::createInstance_sharedptr(\"" << name << "\", \"" << args << "\") called." << std::endl; )
00459 typename factory_t::const_iterator it = m_factory.find(name);
00460 if( m_factory.end() == it ) throw Cj_NotFoundInFactoryException("CjVisitorFactory::createInstance_sharedptr(const std::string & name, const std::string & args, const VisitorArgumentType * ): " + name + " not found in factory");
00461 return Visitor_shared_ptr( it->second->c()( name, args, va ), it->second->d() );
00462 }
00463
00465
00470 std::string getProperty(const std::string & name, const std::string & prop_name) const {
00471 typename factory_t::const_iterator it = m_factory.find(name);
00472 if( m_factory.end() == it ) throw Cj_NotFoundInFactoryException("CjVisitorFactory::getUsage(const std::string & name, const std::string & args ): " + name + " not found in factory");
00473 return it->second->p()( name, prop_name );
00474 }
00475
00477 std::vector < std::string > getRegisteredNames() const {
00478 std::vector < std::string > v;
00479 for(typename factory_t::const_iterator it = m_factory.begin(); it != m_factory.end(); ++it) v.push_back(it->first);
00480 return v;
00481 }
00482
00483 };
00484
00485 }
00486
00487 #endif // _CJVISITORFACTORY_H_