openModeller  Version 1.5.0
AlgorithmFactory.cpp
Go to the documentation of this file.
1 
28 #ifdef WIN32
29 // avoid warnings caused by problems in VC headers
30 #define _SCL_SECURE_NO_DEPRECATE
31 #endif
32 
35 #include <openmodeller/Log.hh>
38 
39 #include <string>
40 #include <list>
41 #include <vector>
42 #include <algorithm>
43 using namespace std;
44 
45 #include <string.h>
46 
47 class testDLLId {
48 public:
49  testDLLId( string const id ) :
50  id(id)
51  {}
52  inline bool operator()( const AlgorithmFactory::DLLPtr& dll ) {
53  return !strcmp( id.c_str(), dll->getMetadata()->id.c_str() );
54  }
55 private:
56  string const id;
57 };
58 
59 /**************************************************************************
60  *
61  * Implementation of AlgorithmFactory::DLL object
62  *
63  * Handles status of dlls.
64  *************************************************************************/
65 
66 /***********************/
67 /*** DLL class definitions ***/
68 
70  _handle( 0 ),
71  _factory( 0 ),
72  _metadata( 0 ),
73  _file()
74 {
75 }
76 
77 AlgorithmFactory::DLL::DLL( const string& file ) :
78  _handle( 0 ),
79  _factory( 0 ),
80  _metadata( 0 ),
81  _file( file )
82 {
83  _handle = dllOpen( file.c_str() );
84 
85  // Opens the DLL file.
86  if ( ! _handle )
87  {
88  const char *error = dllError( _handle );
89  Log::instance()->warn( "Error loading %s: %s\n", file.c_str(), error );
90  goto error;
91  }
92 
93  _factory = (TAlgFactory) dllFunction( _handle, "algorithmFactory" );
94 
95  if ( ! _factory )
96  {
97  const char *error = dllError( _handle );
98  Log::instance()->warn( "Algorithm %s is not openModeller compatible! (TAlgFactory mismatch)\n", file.c_str() );
99  Log::instance()->warn( "Error: %s\n", error );
100  goto error;
101  }
102 
103  _metadata = (TAlgMetadata) dllFunction( _handle, "algorithmMetadata" );
104 
105  if ( ! _metadata )
106  {
107  const char *error = dllError( _handle );
108  Log::instance()->warn( "Algorithm %s is not openModeller compatible! (TAlgMetadata mismatch)\n", file.c_str() );
109  Log::instance()->warn( "Error: %s\n", error );
110  goto error;
111  }
112 
113  return;
114 
115  error:
116  _handle = 0;
117  _factory = 0;
118  _metadata = 0;
119 
120 }
121 
122 /**********************/
123 /*** DLL destructor ***/
124 
126 {
127  if ( _handle ) {
128  Log::instance()->debug( "- Unloading: %s ...currently, dlls are not closed.\n", _file.c_str() );
129  dllClose( _handle );
130  }
131 }
132 
133 /**********************/
134 /*** DLL operator bool() ***/
135 
136 AlgorithmFactory::DLL::operator bool() const
137 {
138  return ( _handle != 0 );
139 }
140 
141 /*************************/
142 /*** DLL new Algorithm ***/
145 {
146  AlgorithmImpl *ai = (*_factory)();
147 
148  return AlgorithmPtr(ai);
149 }
150 
151 /*************************/
152 /*** DLL new Algorithm ***/
153 AlgMetadata const *
155 {
156  return (*_metadata)();
157 }
158 
159 /**************************************************************************
160  *
161  * Implementation of AlgorithmFactory object
162  *
163  *************************************************************************/
164 
165 /*******************/
166 /*** constructor ***/
167 
169  _dlls(),
170  _pluginpath()
171 {
172 }
173 
174 /******************/
175 /*** destructor ***/
176 
178 {
179 }
180 
181 /**************************/
182 /*** Singleton accessor ***/
185 {
186  static AlgorithmFactory theInstance;
187  return theInstance;
188 }
189 
190 /***************************/
191 /*** set Default Alg Dir ***/
192 void
193 AlgorithmFactory::setDefaultAlgDir( std::string const dir )
194 {
196 
197  af._default_alg_dir = dir;
198 }
199 
200 /***************************/
201 /*** get Default Alg Dir ***/
202 std::string
204 {
206 
207  return af._default_alg_dir;
208 }
209 
210 /****************************/
211 /*** available Algorithms ***/
212 AlgMetadata const **
214 {
215 
217 
218  int dll_count = af._dlls.size();
219 
220  // Make room for the algorithms' metadatas.
221  AlgMetadata const **all = new AlgMetadata const *[ dll_count + 1];
222 
223  AlgMetadata const **metadata = all;
224 
225  // If there are no DLLs loaded, return NULL;
226  if ( dll_count > 0 ) {
227 
228  // For each DLL found:
229  ListDLL::iterator dll = af._dlls.begin();
230  for ( ; dll != af._dlls.end(); ++metadata, ++dll )
231  *metadata = (*dll)->getMetadata();
232 
233  }
234  // Null terminated.
235  *metadata = 0;
236 
237  return all;
238 }
239 
240 
241 /********************************/
242 /*** num Available Algorithms ***/
243 int
245 {
247 
248  int dll_count = af._dlls.size();
249 
250  return dll_count;
251 }
252 
253 
254 /***************************/
255 /*** algorithm Metadata ***/
256 AlgMetadata const *
258 {
259  if ( 0 == id.size() ) {
260 
261  string msg = "Algorithm id not specified.\n";
262 
263  Log::instance()->error( msg.c_str() );
264 
265  throw InvalidParameterException( msg );
266  }
267 
269 
270  string const current_id = getCurrentId( id );
271 
272  testDLLId test( current_id );
273  ListDLL::iterator dll = find_if( af._dlls.begin(), af._dlls.end(), test );
274 
275  if ( dll != af._dlls.end() ) {
276 
277  return (*dll)->getMetadata();
278  }
279 
280  string msg("Algorithm ");
281  msg += id;
282  msg += " not found";
283 
284  Log::instance()->error( msg.c_str() );
285 
286  throw InvalidParameterException( msg );
287 }
288 
289 /*********************/
290 /*** new Algorithm ***/
292 AlgorithmFactory::newAlgorithm( string const id )
293 {
295 
296  int dll_count = af._dlls.size();
297 
298  if ( dll_count == 0 ) {
299 
300  string msg = "No algorithms loaded.\n";
301 
302  Log::instance()->error( msg.c_str() );
303 
304  throw AlgorithmException( msg );
305  }
306 
307  string const current_id = getCurrentId( id );
308 
309  testDLLId test( current_id );
310 
311  ListDLL::iterator dll = find_if( af._dlls.begin(), af._dlls.end(), test );
312 
313  if ( dll != af._dlls.end() ) {
314 
315  return (*dll)->newAlgorithm();
316  }
317 
318  string msg("Algorithm ");
319  msg += id;
320  msg += " not found";
321 
322  Log::instance()->error( msg.c_str() );
323 
324  throw InvalidParameterException( msg );
325 }
326 
329 
330  Log::instance()->debug( "Instantiating serialized algorithm\n" );
331 
332  string id = config->getAttribute( "Id" );
333 
334  Log::instance()->debug( "Algorithm id: %s \n" , id.c_str() );
335 
336  AlgorithmPtr alg( newAlgorithm( id ) );
337 
338  if ( ! alg ) {
339 
340  return alg;
341  }
342 
343  alg->setConfiguration( config );
344 
345  return alg;
346 }
347 
348 /*****************/
349 /*** load DLLs ***/
350 int
352 {
353  vector<string> entries = initialPluginPath();
354  vector<string>::iterator it = entries.begin();
355 
356  while( it != entries.end() ) {
357  Log::instance()->debug( "Checking for algs in: [%s]\n" , (*it).c_str() );
358  AlgorithmFactory::addDir( (*it).c_str() );
359  ++it;
360  }
361 
362  return 1;
363 }
364 
365 int
366 AlgorithmFactory::addDir( const string& dir )
367 {
369 
370  return af.p_addDir( dir );
371 }
372 
373 /****************/
374 /*** p_addDir ***/
375 int
376 AlgorithmFactory::p_addDir( const string& dir )
377 {
378  if ( dir.length() ) {
379 
380  vector<string> entries = scanDirectory( dir );
381 
382  if ( entries.empty() ) {
383 
384  Log::instance()->warn( "No algorithm found in directory [%s]\n", dir.c_str() );
385  return 0;
386  }
387 
388  vector<string>::const_iterator it = entries.begin();
389 
390  while( it != entries.end() ) {
391 
392  p_addDll( *it );
393 
394  ++it;
395  }
396  }
397 
398  return _dlls.size();
399 }
400 
401 /*****************/
402 /*** load one dll ***/
403 bool
404 AlgorithmFactory::addDll( const string& file )
405 {
407 
408  return af.p_addDll( file );
409 }
410 
411 /****************/
412 /*** p_addDll ***/
413 bool
414 AlgorithmFactory::p_addDll( const string& file )
415 {
416  Log::instance()->debug( "- Loading: %s ...\n", file.c_str() );
417 
418  // Create a new DLL for each directory entry found.
419  DLLPtr dll( new DLL( file.c_str() ) );
420 
421  // Test if the dll was successfully loaded.
422  if ( !(*dll) ) {
423  return false;
424  }
425 
426  Log::instance()->debug( "- Successfully Loaded %s\n", file.c_str() );
427  _dlls.push_back( dll );
428  return true;
429 
430 }
431 
432 /*************************/
433 /*** get configuration ***/
436 {
437  ConfigurationPtr config( new ConfigurationImpl("Algorithms") );
438 
440 
441  int dll_count = af._dlls.size();
442 
443  // If there are any algorithms
444  if ( dll_count > 0 ) {
445 
446  // For each algorithm
447  ListDLL::iterator dll = af._dlls.begin();
448 
449  for ( ; dll != af._dlls.end(); ++dll ) {
450 
451  ConfigurationPtr alg_meta_config( new ConfigurationImpl( "Algorithm" ) );
452 
453  AlgMetadata const *algMetadata = (*dll)->getMetadata();
454 
455  alg_meta_config->addNameValue( "Id", algMetadata->id );
456  alg_meta_config->addNameValue( "Version", algMetadata->version );
457 
458  ConfigurationPtr alg_name_config( new ConfigurationImpl( "Name" ) );
459  alg_name_config->setValue( algMetadata->name );
460  alg_meta_config->addSubsection( alg_name_config );
461 
462  ConfigurationPtr alg_overview_config( new ConfigurationImpl( "Overview" ) );
463  alg_overview_config->setValue( algMetadata->overview );
464  alg_meta_config->addSubsection( alg_overview_config );
465 
466  ConfigurationPtr alg_description_config( new ConfigurationImpl( "Description" ) );
467  alg_description_config->setValue( algMetadata->description );
468  alg_meta_config->addSubsection( alg_description_config );
469 
470  ConfigurationPtr alg_designers_config( new ConfigurationImpl( "Designers" ) );
471  ConfigurationPtr alg_designer_config( new ConfigurationImpl( "Designer" ) );
472  alg_designer_config->addNameValue( "Name", algMetadata->author );
473  alg_designers_config->addSubsection( alg_designer_config );
474  alg_meta_config->addSubsection( alg_designers_config );
475 
476  ConfigurationPtr alg_bibliography_config( new ConfigurationImpl( "Bibliography" ) );
477  alg_bibliography_config->setValue( algMetadata->biblio );
478  alg_meta_config->addSubsection( alg_bibliography_config );
479 
480  ConfigurationPtr alg_developers_config( new ConfigurationImpl( "Developers" ) );
481  ConfigurationPtr alg_developer_config( new ConfigurationImpl( "Developer" ) );
482  alg_developer_config->addNameValue( "Name", algMetadata->code_author );
483  alg_developer_config->addNameValue( "Contact", algMetadata->contact );
484  alg_developers_config->addSubsection( alg_developer_config );
485  alg_meta_config->addSubsection( alg_developers_config );
486 
487  ConfigurationPtr alg_categorical_config( new ConfigurationImpl( "AcceptsCategoricalMaps" ) );
488  char const *accepts_categorical = ( algMetadata->categorical ) ? "1" : "0";
489  alg_categorical_config->setValue( accepts_categorical );
490  alg_meta_config->addSubsection( alg_categorical_config );
491 
492  ConfigurationPtr alg_absences_config( new ConfigurationImpl( "RequiresAbsencePoints" ) );
493  char const *requires_absences = ( algMetadata->absence ) ? "1" : "0";
494  alg_absences_config->setValue( requires_absences );
495  alg_meta_config->addSubsection( alg_absences_config );
496 
497  ConfigurationPtr params_config( new ConfigurationImpl( "Parameters" ) );
498 
499  AlgParamMetadata *param = algMetadata->param;
500 
501  // Include parameters metadata
502  for ( int i=0 ; i < algMetadata->nparam; param++, i++ ) {
503 
504  ConfigurationPtr param_config( new ConfigurationImpl( "Parameter" ) );
505 
506  param_config->addNameValue( "Id", param->id );
507 
508  ConfigurationPtr param_name_config( new ConfigurationImpl( "Name" ) );
509  param_name_config->setValue( param->name );
510  param_config->addSubsection( param_name_config );
511 
512  string datatype("?");
513 
514  if ( param->type == Integer ) {
515 
516  datatype = "Integer";
517  }
518  else if ( param->type == Real ) {
519 
520  datatype = "Real";
521  }
522  else if ( param->type == String ) {
523 
524  datatype = "String";
525  }
526 
527  ConfigurationPtr param_type_config( new ConfigurationImpl( "Type" ) );
528  param_type_config->setValue( datatype.c_str() );
529  param_config->addSubsection( param_type_config );
530 
531  ConfigurationPtr param_overview_config( new ConfigurationImpl( "Overview" ) );
532  param_overview_config->setValue( param->overview );
533  param_config->addSubsection( param_overview_config );
534 
535  ConfigurationPtr param_description_config( new ConfigurationImpl( "Description" ) );
536  param_description_config->setValue( param->description );
537  param_config->addSubsection( param_description_config );
538 
539  if ( param->has_min || param->has_max ) {
540 
541  ConfigurationPtr param_range_config( new ConfigurationImpl( "AcceptedRange" ) );
542 
543  if ( param->has_min ) {
544 
545  param_range_config->addNameValue( "Min", param->min_val );
546  }
547  if ( param->has_max ) {
548 
549  param_range_config->addNameValue( "Max", param->max_val );
550  }
551 
552  param_config->addSubsection( param_range_config );
553  }
554 
555  ConfigurationPtr param_default_config( new ConfigurationImpl( "Default" ) );
556  param_default_config->setValue( param->typical );
557  param_config->addSubsection( param_default_config );
558 
559  params_config->addSubsection( param_config );
560  }
561 
562  alg_meta_config->addSubsection( params_config );
563 
564  config->addSubsection( alg_meta_config );
565  }
566  }
567 
568  return config;
569 }
570 
571 
572 /**********************/
573 /*** get current id ***/
574 string const
575 AlgorithmFactory::getCurrentId( string const algorithm_id )
576 {
577  if ( algorithm_id == "EnvironmentalDistance" ) {
578 
579  return string( "ENVDIST" );
580  }
581  else if ( algorithm_id == "Bioclim") {
582 
583  return string( "BIOCLIM" );
584  }
585  else if ( algorithm_id == "EnvelopeScore" ) {
586 
587  return string( "ENVSCORE" );
588  }
589  else if ( algorithm_id == "AquaMaps" ) {
590 
591  return string( "AQUAMAPS" );
592  }
593 
594  return algorithm_id;
595 }
vector< string > scanDirectory(string dir)
int categorical
If not zero accept categorical maps.
Definition: AlgMetadata.hh:87
static AlgorithmFactory & getInstance()
void warn(const char *format,...)
'Warn' level.
Definition: Log.cpp:273
testDLLId(string const id)
std::string author
Algorithm's author.
Definition: AlgMetadata.hh:81
static AlgorithmPtr newAlgorithm(std::string const id)
void * dllFunction(DLLHandle handle, char const *function_name)
Definition: os_specific.cpp:70
static AlgMetadata const ** availableAlgorithms()
AlgMetadata const * getMetadata()
static std::string getDefaultAlgDir()
int dllClose(DLLHandle handle)
Definition: os_specific.cpp:79
static Log * instance()
Returns the instance pointer, creating the object on the first call.
Definition: Log.cpp:45
AlgorithmImpl *(* TAlgFactory)()
Definition: Algorithm.hh:63
std::string id
Identifier to be used by programmers.
Definition: AlgMetadata.hh:75
Scalar max_val
Maximum parameter value.
Definition: AlgMetadata.hh:61
AlgParamMetadata * param
Definition: AlgMetadata.hh:91
AlgParamDatatype type
Real, Integer, String.
Definition: AlgMetadata.hh:54
std::string code_author
Who implemented.
Definition: AlgMetadata.hh:84
std::string contact
code_author contact (eg e-mail).
Definition: AlgMetadata.hh:85
ReferenceCountedPointer< AlgorithmImpl > AlgorithmPtr
Definition: Algorithm.hh:53
int has_max
Zero if the parameter has no upper limit.
Definition: AlgMetadata.hh:60
Scalar min_val
Minimum parameter value.
Definition: AlgMetadata.hh:59
void error(const char *format,...)
'Error' level.
Definition: Log.cpp:290
int p_addDir(const std::string &dir)
std::string name
Name to be shown to end users.
Definition: AlgMetadata.hh:53
static ConfigurationPtr getConfiguration()
static void setDefaultAlgDir(std::string const dir)
bool operator()(const AlgorithmFactory::DLLPtr &dll)
std::string typical
Typical parameter value.
Definition: AlgMetadata.hh:62
std::string _default_alg_dir
std::string id
Identifier to be used by programmers.
Definition: AlgMetadata.hh:52
static int searchDefaultDirs()
static bool addDll(const std::string &file)
vector< string > initialPluginPath()
int nparam
Number of parameters.
Definition: AlgMetadata.hh:89
std::string name
Name to be shown to end users.
Definition: AlgMetadata.hh:76
static int numAvailableAlgorithms()
bool p_addDll(const std::string &file)
static AlgMetadata const * algorithmMetadata(std::string const algorithm_id)
static std::string const getCurrentId(std::string const algorithm_id)
AlgMetadata *(* TAlgMetadata)()
Definition: Algorithm.hh:64
std::string biblio
Bibliography reference.
Definition: AlgMetadata.hh:82
int has_min
Zero if the parameter has no lower limit.
Definition: AlgMetadata.hh:58
std::string version
Built version.
Definition: AlgMetadata.hh:77
string const id
std::string description
Detailed description.
Definition: AlgMetadata.hh:79
int absence
Needs absence points to run.
Definition: AlgMetadata.hh:88
DLLHandle dllOpen(char const *dll_file_name)
Definition: os_specific.cpp:61
std::string description
Detailed description.
Definition: AlgMetadata.hh:56
static int addDir(const std::string &dirs)
void debug(const char *format,...)
'Debug' level.
Definition: Log.cpp:237
const char * dllError(DLLHandle)
Definition: os_specific.cpp:88
AlgMetadata metadata
Definition: garp.cpp:134
std::string overview
Short description.
Definition: AlgMetadata.hh:55
std::string overview
Short description.
Definition: AlgMetadata.hh:78
static char error[256]
Definition: FileParser.cpp:42