openModeller  Version 1.4.0
AlgorithmFactory.cpp
Go to the documentation of this file.
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 }