openModeller
Version 1.4.0
|
00001 00028 #ifdef WIN32 00029 // avoid warnings caused by problems in VC headers 00030 #define _SCL_SECURE_NO_DEPRECATE 00031 #endif 00032 00033 #include <openmodeller/AlgorithmFactory.hh> 00034 #include <openmodeller/Algorithm.hh> 00035 #include <openmodeller/Log.hh> 00036 #include <openmodeller/Configuration.hh> 00037 #include <openmodeller/Exceptions.hh> 00038 00039 #include <string> 00040 #include <list> 00041 #include <vector> 00042 #include <algorithm> 00043 using namespace std; 00044 00045 #include <string.h> 00046 00047 class testDLLId { 00048 public: 00049 testDLLId( string const id ) : 00050 id(id) 00051 {} 00052 inline bool operator()( const AlgorithmFactory::DLLPtr& dll ) { 00053 return !strcmp( id.c_str(), dll->getMetadata()->id.c_str() ); 00054 } 00055 private: 00056 string const id; 00057 }; 00058 00059 /************************************************************************** 00060 * 00061 * Implementation of AlgorithmFactory::DLL object 00062 * 00063 * Handles status of dlls. 00064 *************************************************************************/ 00065 00066 /***********************/ 00067 /*** DLL class definitions ***/ 00068 00069 AlgorithmFactory::DLL::DLL() : 00070 _handle( 0 ), 00071 _factory( 0 ), 00072 _metadata( 0 ), 00073 _file() 00074 { 00075 } 00076 00077 AlgorithmFactory::DLL::DLL( const string& file ) : 00078 _handle( 0 ), 00079 _factory( 0 ), 00080 _metadata( 0 ), 00081 _file( file ) 00082 { 00083 _handle = dllOpen( file.c_str() ); 00084 00085 // Opens the DLL file. 00086 if ( ! _handle ) 00087 { 00088 const char *error = dllError( _handle ); 00089 Log::instance()->warn( "Error loading %s: %s\n", file.c_str(), error ); 00090 goto error; 00091 } 00092 00093 _factory = (TAlgFactory) dllFunction( _handle, "algorithmFactory" ); 00094 00095 if ( ! _factory ) 00096 { 00097 const char *error = dllError( _handle ); 00098 Log::instance()->warn( "Algorithm %s is not openModeller compatible! (TAlgFactory mismatch)\n", file.c_str() ); 00099 Log::instance()->warn( "Error: %s\n", error ); 00100 goto error; 00101 } 00102 00103 _metadata = (TAlgMetadata) dllFunction( _handle, "algorithmMetadata" ); 00104 00105 if ( ! _metadata ) 00106 { 00107 const char *error = dllError( _handle ); 00108 Log::instance()->warn( "Algorithm %s is not openModeller compatible! (TAlgMetadata mismatch)\n", file.c_str() ); 00109 Log::instance()->warn( "Error: %s\n", error ); 00110 goto error; 00111 } 00112 00113 return; 00114 00115 error: 00116 _handle = 0; 00117 _factory = 0; 00118 _metadata = 0; 00119 00120 } 00121 00122 /**********************/ 00123 /*** DLL destructor ***/ 00124 00125 AlgorithmFactory::DLL::~DLL() 00126 { 00127 if ( _handle ) { 00128 Log::instance()->debug( "- Unloading: %s ...currently, dlls are not closed.\n", _file.c_str() ); 00129 dllClose( _handle ); 00130 } 00131 } 00132 00133 /**********************/ 00134 /*** DLL operator bool() ***/ 00135 00136 AlgorithmFactory::DLL::operator bool() const 00137 { 00138 return ( _handle != 0 ); 00139 } 00140 00141 /*************************/ 00142 /*** DLL new Algorithm ***/ 00143 AlgorithmPtr 00144 AlgorithmFactory::DLL::newAlgorithm() 00145 { 00146 AlgorithmImpl *ai = (*_factory)(); 00147 00148 return AlgorithmPtr(ai); 00149 } 00150 00151 /*************************/ 00152 /*** DLL new Algorithm ***/ 00153 AlgMetadata const * 00154 AlgorithmFactory::DLL::getMetadata() 00155 { 00156 return (*_metadata)(); 00157 } 00158 00159 /************************************************************************** 00160 * 00161 * Implementation of AlgorithmFactory object 00162 * 00163 *************************************************************************/ 00164 00165 /*******************/ 00166 /*** constructor ***/ 00167 00168 AlgorithmFactory::AlgorithmFactory() : 00169 _dlls(), 00170 _pluginpath() 00171 { 00172 } 00173 00174 /******************/ 00175 /*** destructor ***/ 00176 00177 AlgorithmFactory::~AlgorithmFactory() 00178 { 00179 } 00180 00181 /**************************/ 00182 /*** Singleton accessor ***/ 00183 AlgorithmFactory& 00184 AlgorithmFactory::getInstance() 00185 { 00186 static AlgorithmFactory theInstance; 00187 return theInstance; 00188 } 00189 00190 /***************************/ 00191 /*** set Default Alg Dir ***/ 00192 void 00193 AlgorithmFactory::setDefaultAlgDir( std::string const dir ) 00194 { 00195 AlgorithmFactory& af = getInstance(); 00196 00197 af._default_alg_dir = dir; 00198 } 00199 00200 /***************************/ 00201 /*** get Default Alg Dir ***/ 00202 std::string 00203 AlgorithmFactory::getDefaultAlgDir() 00204 { 00205 AlgorithmFactory& af = getInstance(); 00206 00207 return af._default_alg_dir; 00208 } 00209 00210 /****************************/ 00211 /*** available Algorithms ***/ 00212 AlgMetadata const ** 00213 AlgorithmFactory::availableAlgorithms() 00214 { 00215 00216 AlgorithmFactory& af = getInstance(); 00217 00218 int dll_count = af._dlls.size(); 00219 00220 // Make room for the algorithms' metadatas. 00221 AlgMetadata const **all = new AlgMetadata const *[ dll_count + 1]; 00222 00223 AlgMetadata const **metadata = all; 00224 00225 // If there are no DLLs loaded, return NULL; 00226 if ( dll_count > 0 ) { 00227 00228 // For each DLL found: 00229 ListDLL::iterator dll = af._dlls.begin(); 00230 for ( ; dll != af._dlls.end(); ++metadata, ++dll ) 00231 *metadata = (*dll)->getMetadata(); 00232 00233 } 00234 // Null terminated. 00235 *metadata = 0; 00236 00237 return all; 00238 } 00239 00240 00241 /********************************/ 00242 /*** num Available Algorithms ***/ 00243 int 00244 AlgorithmFactory::numAvailableAlgorithms() 00245 { 00246 AlgorithmFactory& af = getInstance(); 00247 00248 int dll_count = af._dlls.size(); 00249 00250 return dll_count; 00251 } 00252 00253 00254 /***************************/ 00255 /*** algorithm Metadata ***/ 00256 AlgMetadata const * 00257 AlgorithmFactory::algorithmMetadata( string const id ) 00258 { 00259 if ( 0 == id.size() ) { 00260 00261 string msg = "Algorithm id not specified.\n"; 00262 00263 Log::instance()->error( msg.c_str() ); 00264 00265 throw InvalidParameterException( msg ); 00266 } 00267 00268 AlgorithmFactory& af = getInstance(); 00269 00270 string const current_id = getCurrentId( id ); 00271 00272 testDLLId test( current_id ); 00273 ListDLL::iterator dll = find_if( af._dlls.begin(), af._dlls.end(), test ); 00274 00275 if ( dll != af._dlls.end() ) { 00276 00277 return (*dll)->getMetadata(); 00278 } 00279 00280 string msg("Algorithm "); 00281 msg += id; 00282 msg += " not found"; 00283 00284 Log::instance()->error( msg.c_str() ); 00285 00286 throw InvalidParameterException( msg ); 00287 } 00288 00289 /*********************/ 00290 /*** new Algorithm ***/ 00291 AlgorithmPtr 00292 AlgorithmFactory::newAlgorithm( string const id ) 00293 { 00294 AlgorithmFactory& af = getInstance(); 00295 00296 int dll_count = af._dlls.size(); 00297 00298 if ( dll_count == 0 ) { 00299 00300 string msg = "No algorithms loaded.\n"; 00301 00302 Log::instance()->error( msg.c_str() ); 00303 00304 throw AlgorithmException( msg ); 00305 } 00306 00307 string const current_id = getCurrentId( id ); 00308 00309 testDLLId test( current_id ); 00310 00311 ListDLL::iterator dll = find_if( af._dlls.begin(), af._dlls.end(), test ); 00312 00313 if ( dll != af._dlls.end() ) { 00314 00315 return (*dll)->newAlgorithm(); 00316 } 00317 00318 string msg("Algorithm "); 00319 msg += id; 00320 msg += " not found"; 00321 00322 Log::instance()->error( msg.c_str() ); 00323 00324 throw InvalidParameterException( msg ); 00325 } 00326 00327 AlgorithmPtr 00328 AlgorithmFactory::newAlgorithm( const ConstConfigurationPtr & config ) { 00329 00330 Log::instance()->debug( "Instantiating serialized algorithm\n" ); 00331 00332 string id = config->getAttribute( "Id" ); 00333 00334 Log::instance()->debug( "Algorithm id: %s \n" , id.c_str() ); 00335 00336 AlgorithmPtr alg( newAlgorithm( id ) ); 00337 00338 if ( ! alg ) { 00339 00340 return alg; 00341 } 00342 00343 alg->setConfiguration( config ); 00344 00345 return alg; 00346 } 00347 00348 /*****************/ 00349 /*** load DLLs ***/ 00350 int 00351 AlgorithmFactory::searchDefaultDirs( ) 00352 { 00353 vector<string> entries = initialPluginPath(); 00354 vector<string>::iterator it = entries.begin(); 00355 00356 while( it != entries.end() ) { 00357 Log::instance()->debug( "Checking for algs in: [%s]\n" , (*it).c_str() ); 00358 AlgorithmFactory::addDir( (*it).c_str() ); 00359 ++it; 00360 } 00361 00362 return 1; 00363 } 00364 00365 int 00366 AlgorithmFactory::addDir( const string& dir ) 00367 { 00368 AlgorithmFactory& af = getInstance(); 00369 00370 return af.p_addDir( dir ); 00371 } 00372 00373 /****************/ 00374 /*** p_addDir ***/ 00375 int 00376 AlgorithmFactory::p_addDir( const string& dir ) 00377 { 00378 if ( dir.length() ) { 00379 00380 vector<string> entries = scanDirectory( dir ); 00381 00382 if ( entries.empty() ) { 00383 00384 Log::instance()->warn( "No algorithm found in directory [%s]\n", dir.c_str() ); 00385 return 0; 00386 } 00387 00388 vector<string>::const_iterator it = entries.begin(); 00389 00390 while( it != entries.end() ) { 00391 00392 p_addDll( *it ); 00393 00394 ++it; 00395 } 00396 } 00397 00398 return _dlls.size(); 00399 } 00400 00401 /*****************/ 00402 /*** load one dll ***/ 00403 bool 00404 AlgorithmFactory::addDll( const string& file ) 00405 { 00406 AlgorithmFactory& af = getInstance(); 00407 00408 return af.p_addDll( file ); 00409 } 00410 00411 /****************/ 00412 /*** p_addDll ***/ 00413 bool 00414 AlgorithmFactory::p_addDll( const string& file ) 00415 { 00416 Log::instance()->debug( "- Loading: %s ...\n", file.c_str() ); 00417 00418 // Create a new DLL for each directory entry found. 00419 DLLPtr dll( new DLL( file.c_str() ) ); 00420 00421 // Test if the dll was successfully loaded. 00422 if ( !(*dll) ) { 00423 return false; 00424 } 00425 00426 Log::instance()->debug( "- Successfully Loaded %s\n", file.c_str() ); 00427 _dlls.push_back( dll ); 00428 return true; 00429 00430 } 00431 00432 /*************************/ 00433 /*** get configuration ***/ 00434 ConfigurationPtr 00435 AlgorithmFactory::getConfiguration() 00436 { 00437 ConfigurationPtr config( new ConfigurationImpl("Algorithms") ); 00438 00439 AlgorithmFactory& af = getInstance(); 00440 00441 int dll_count = af._dlls.size(); 00442 00443 // If there are any algorithms 00444 if ( dll_count > 0 ) { 00445 00446 // For each algorithm 00447 ListDLL::iterator dll = af._dlls.begin(); 00448 00449 for ( ; dll != af._dlls.end(); ++dll ) { 00450 00451 ConfigurationPtr alg_meta_config( new ConfigurationImpl( "Algorithm" ) ); 00452 00453 AlgMetadata const *algMetadata = (*dll)->getMetadata(); 00454 00455 alg_meta_config->addNameValue( "Id", algMetadata->id ); 00456 alg_meta_config->addNameValue( "Version", algMetadata->version ); 00457 00458 ConfigurationPtr alg_name_config( new ConfigurationImpl( "Name" ) ); 00459 alg_name_config->setValue( algMetadata->name ); 00460 alg_meta_config->addSubsection( alg_name_config ); 00461 00462 ConfigurationPtr alg_overview_config( new ConfigurationImpl( "Overview" ) ); 00463 alg_overview_config->setValue( algMetadata->overview ); 00464 alg_meta_config->addSubsection( alg_overview_config ); 00465 00466 ConfigurationPtr alg_description_config( new ConfigurationImpl( "Description" ) ); 00467 alg_description_config->setValue( algMetadata->description ); 00468 alg_meta_config->addSubsection( alg_description_config ); 00469 00470 ConfigurationPtr alg_designers_config( new ConfigurationImpl( "Designers" ) ); 00471 ConfigurationPtr alg_designer_config( new ConfigurationImpl( "Designer" ) ); 00472 alg_designer_config->addNameValue( "Name", algMetadata->author ); 00473 alg_designers_config->addSubsection( alg_designer_config ); 00474 alg_meta_config->addSubsection( alg_designers_config ); 00475 00476 ConfigurationPtr alg_bibliography_config( new ConfigurationImpl( "Bibliography" ) ); 00477 alg_bibliography_config->setValue( algMetadata->biblio ); 00478 alg_meta_config->addSubsection( alg_bibliography_config ); 00479 00480 ConfigurationPtr alg_developers_config( new ConfigurationImpl( "Developers" ) ); 00481 ConfigurationPtr alg_developer_config( new ConfigurationImpl( "Developer" ) ); 00482 alg_developer_config->addNameValue( "Name", algMetadata->code_author ); 00483 alg_developer_config->addNameValue( "Contact", algMetadata->contact ); 00484 alg_developers_config->addSubsection( alg_developer_config ); 00485 alg_meta_config->addSubsection( alg_developers_config ); 00486 00487 ConfigurationPtr alg_categorical_config( new ConfigurationImpl( "AcceptsCategoricalMaps" ) ); 00488 char const *accepts_categorical = ( algMetadata->categorical ) ? "1" : "0"; 00489 alg_categorical_config->setValue( accepts_categorical ); 00490 alg_meta_config->addSubsection( alg_categorical_config ); 00491 00492 ConfigurationPtr alg_absences_config( new ConfigurationImpl( "RequiresAbsencePoints" ) ); 00493 char const *requires_absences = ( algMetadata->absence ) ? "1" : "0"; 00494 alg_absences_config->setValue( requires_absences ); 00495 alg_meta_config->addSubsection( alg_absences_config ); 00496 00497 ConfigurationPtr params_config( new ConfigurationImpl( "Parameters" ) ); 00498 00499 AlgParamMetadata *param = algMetadata->param; 00500 00501 // Include parameters metadata 00502 for ( int i=0 ; i < algMetadata->nparam; param++, i++ ) { 00503 00504 ConfigurationPtr param_config( new ConfigurationImpl( "Parameter" ) ); 00505 00506 param_config->addNameValue( "Id", param->id ); 00507 00508 ConfigurationPtr param_name_config( new ConfigurationImpl( "Name" ) ); 00509 param_name_config->setValue( param->name ); 00510 param_config->addSubsection( param_name_config ); 00511 00512 string datatype("?"); 00513 00514 if ( param->type == Integer ) { 00515 00516 datatype = "Integer"; 00517 } 00518 else if ( param->type == Real ) { 00519 00520 datatype = "Real"; 00521 } 00522 else if ( param->type == String ) { 00523 00524 datatype = "String"; 00525 } 00526 00527 ConfigurationPtr param_type_config( new ConfigurationImpl( "Type" ) ); 00528 param_type_config->setValue( datatype.c_str() ); 00529 param_config->addSubsection( param_type_config ); 00530 00531 ConfigurationPtr param_overview_config( new ConfigurationImpl( "Overview" ) ); 00532 param_overview_config->setValue( param->overview ); 00533 param_config->addSubsection( param_overview_config ); 00534 00535 ConfigurationPtr param_description_config( new ConfigurationImpl( "Description" ) ); 00536 param_description_config->setValue( param->description ); 00537 param_config->addSubsection( param_description_config ); 00538 00539 if ( param->has_min || param->has_max ) { 00540 00541 ConfigurationPtr param_range_config( new ConfigurationImpl( "AcceptedRange" ) ); 00542 00543 if ( param->has_min ) { 00544 00545 param_range_config->addNameValue( "Min", param->min_val ); 00546 } 00547 if ( param->has_max ) { 00548 00549 param_range_config->addNameValue( "Max", param->max_val ); 00550 } 00551 00552 param_config->addSubsection( param_range_config ); 00553 } 00554 00555 ConfigurationPtr param_default_config( new ConfigurationImpl( "Default" ) ); 00556 param_default_config->setValue( param->typical ); 00557 param_config->addSubsection( param_default_config ); 00558 00559 params_config->addSubsection( param_config ); 00560 } 00561 00562 alg_meta_config->addSubsection( params_config ); 00563 00564 config->addSubsection( alg_meta_config ); 00565 } 00566 } 00567 00568 return config; 00569 } 00570 00571 00572 /**********************/ 00573 /*** get current id ***/ 00574 string const 00575 AlgorithmFactory::getCurrentId( string const algorithm_id ) 00576 { 00577 if ( algorithm_id == "EnvironmentalDistance" ) { 00578 00579 return string( "ENVDIST" ); 00580 } 00581 else if ( algorithm_id == "Bioclim") { 00582 00583 return string( "BIOCLIM" ); 00584 } 00585 else if ( algorithm_id == "EnvelopeScore" ) { 00586 00587 return string( "ENVSCORE" ); 00588 } 00589 else if ( algorithm_id == "AquaMaps" ) { 00590 00591 return string( "AQUAMAPS" ); 00592 } 00593 00594 return algorithm_id; 00595 }