]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Interface/Plugins.cxx
42ab2cc77ded0fd88249a1c6a8bf9f6b8b1b70d5
[cpPlugins.git] / lib / cpPlugins / Interface / Plugins.cxx
1 #include <cpPlugins/Interface/Plugins.h>
2 #include <cpPlugins/OS/DLLManager.h>
3 #include <cpPlugins/Interface/Dirent.h>
4 #include <cpExtensions/Utility.h>
5
6 // -------------------------------------------------------------------------
7 cpPlugins::Interface::Plugins::
8 Pointer cpPlugins::Interface::Plugins::
9 New( )
10 {
11   static Pointer singleton = NULL;
12   if( singleton.IsNull( ) )
13     singleton = new Self( );
14   return( singleton );
15 }
16
17 // -------------------------------------------------------------------------
18 itk::LightObject::Pointer cpPlugins::Interface::Plugins::
19 CreateAnother( ) const
20 {
21   itk::LightObject::Pointer smartPtr;
22   smartPtr = NULL;
23   return( smartPtr );
24 }
25
26 // -------------------------------------------------------------------------
27 cpPlugins::Interface::Plugins::
28 Pointer cpPlugins::Interface::Plugins::
29 Clone( ) const
30 {
31   Pointer r = NULL;
32   return( r );
33 }
34
35 // -------------------------------------------------------------------------
36 cpPlugins::Interface::Plugins::
37 TStrings cpPlugins::Interface::Plugins::
38 GetLibraries( ) const
39 {
40   TStrings res;
41   for(
42     auto i = this->m_Libraries.begin( ); i != this->m_Libraries.end( ); ++i
43     )
44     res.insert( i->first );
45   return( res );
46 }
47
48 // -------------------------------------------------------------------------
49 cpPlugins::Interface::Plugins::
50 TStrings cpPlugins::Interface::Plugins::
51 GetPlugins( ) const
52 {
53   TStrings res;
54   for( auto i = this->m_Plugins.begin( ); i != this->m_Plugins.end( ); ++i )
55     res.insert( i->first );
56   return( res );
57 }
58
59 // -------------------------------------------------------------------------
60 cpPlugins::Interface::Plugins::
61 TStrings cpPlugins::Interface::Plugins::
62 GetCategories( ) const
63 {
64   TStrings res;
65   for( auto i = this->m_Filters.begin( ); i != this->m_Filters.end( ); ++i )
66     res.insert( i->first );
67   return( res );
68 }
69
70 // -------------------------------------------------------------------------
71 cpPlugins::Interface::Plugins::
72 TStrings cpPlugins::Interface::Plugins::
73 GetFilters( const std::string& category ) const
74 {
75   TStrings res;
76   auto cIt = this->m_Filters.find( category );
77   if( cIt != this->m_Filters.end( ) )
78     for( auto i = cIt->second.begin( ); i != cIt->second.end( ); ++i )
79       res.insert( i->first );
80   return( res );
81 }
82
83 // -------------------------------------------------------------------------
84 void cpPlugins::Interface::Plugins::
85 AddEnvironments( const std::string& new_environment )
86 {
87   std::vector< std::string > tokens;
88   cpExtensions::Tokenize( tokens, new_environment, cpPlugins_ENV_SEPARATOR );
89   for( auto i = tokens.begin( ); i != tokens.end( ); ++i )
90   {
91     std::stringstream dir;
92     dir << cpExtensions::CanonicalPath( *i );
93     if( dir.str( ) != "" )
94       this->m_Paths.insert( dir.str( ) );
95
96   } // rof
97 }
98
99 // -------------------------------------------------------------------------
100 void cpPlugins::Interface::Plugins::
101 LoadEnvironments( )
102 {
103   std::stringstream all_errors;
104   for( auto d = this->m_Paths.begin( ); d != this->m_Paths.end( ); ++d )
105   {
106     std::stringstream name;
107     name << *d << cpPlugins_CONFIG;
108     std::string buffer;
109     if( cpExtensions::Read( buffer, name.str( ) ) )
110     {
111       std::istringstream input( buffer );
112       for( std::string line; std::getline( input, line ); )
113       {
114         std::vector< std::string > tokens;
115         cpExtensions::Tokenize( tokens, line, "@" );
116         std::string library_file = "";
117         if( tokens[ 0 ] == "local" )
118           library_file =
119             cpExtensions::CanonicalPath(
120               *d + std::string( cpPlugins_LIB_PREFIX ) +
121               tokens[ 1 ] + std::string( cpPlugins_LIB_EXT )
122               );
123         else if( tokens[ 0 ] == "global" )
124           library_file = tokens[ 1 ];
125
126         if( library_file != "" )
127         {
128           std::string error = "";
129           void* hnd = cpPlugins::OS::DLLManager::Load( library_file, error );
130           if( hnd != NULL )
131             this->m_Libraries[ library_file ] = hnd;
132           else
133             all_errors << " ; " << error;
134
135         } // fi
136
137       } // rof
138
139     } // fi
140
141   } // rof
142
143   // Throw errors
144   if( all_errors.str( ) != "" )
145     throw std::runtime_error(
146       std::string( "Loading environment libraries errors: " ) +
147       all_errors.str( )
148       );
149 }
150
151 // -------------------------------------------------------------------------
152 void cpPlugins::Interface::Plugins::
153 SaveEnvironments( const std::string& dir ) const
154 {
155   std::stringstream buffer;
156   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
157     buffer << *i << std::endl;
158
159   std::stringstream fname;
160   fname << dir;
161   if( !cpExtensions::IsPathSeparator( dir.back( ) ) )
162     fname << cpExtensions_PATH_SEPARATOR;
163   fname << cpPlugins_PATHS;
164   if( !cpExtensions::Write( buffer.str( ), fname.str( ) ) )
165     throw std::runtime_error( "Error writing environment file." );
166 }
167
168 // -------------------------------------------------------------------------
169 void cpPlugins::Interface::Plugins::
170 OpenEnvironments( const std::string& dir )
171 {
172   std::vector< std::string > tokens;
173   cpExtensions::Tokenize( tokens, dir, cpPlugins_ENV_SEPARATOR );
174   for( auto tIt = tokens.begin( ); tIt != tokens.end( ); ++tIt )
175   {
176     std::stringstream fname;
177     fname << *tIt;
178     if( !cpExtensions::IsPathSeparator( dir.back( ) ) )
179       fname << cpExtensions_PATH_SEPARATOR;
180     fname << cpPlugins_PATHS;
181     std::string buffer;
182     if( cpExtensions::Read( buffer, fname.str( ) ) )
183     {
184       std::istringstream input( buffer );
185       std::stringstream paths;
186       for( std::string line; std::getline( input, line ); )
187         paths << line << cpPlugins_ENV_SEPARATOR;
188       this->AddEnvironments( paths.str( ) );
189     }
190     else
191     {
192       bool success = true;
193       try
194       {
195         this->LoadDirectory( dir );
196       }
197       catch( ... )
198       {
199         success = false;
200
201       } // yrt
202       if( success )
203         this->AddEnvironments( dir );
204
205     } // fi
206
207   } // rof
208 }
209
210 // -------------------------------------------------------------------------
211 void cpPlugins::Interface::Plugins::
212 LoadFile( const std::string& fname )
213 {
214   // Resolve canonical filename
215   std::string can_name = cpExtensions::CanonicalPath( fname );
216   if( can_name == "" )
217     throw std::runtime_error(
218       std::string( "Loading file: can't find library \"" ) +
219       fname +
220       std::string( "\"" )
221       );
222   if( this->m_Plugins.find( can_name ) != this->m_Plugins.end( ) )
223     return;
224
225   // Load the library
226   std::string error = "";
227   void* hnd = cpPlugins::OS::DLLManager::Load( can_name, error );
228   if( hnd == NULL )
229     throw std::runtime_error(
230       std::string( "Loading plugin library: " ) + error
231       );
232
233   // Get plugins name
234   typedef const char* ( *_TFunction )( );
235   _TFunction plugins_name_function = ( _TFunction )(
236     cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, "cpPlugins_Name" )
237     );
238   if( plugins_name_function == NULL )
239   {
240     cpPlugins::OS::DLLManager::UnLoad( hnd );
241     throw std::runtime_error(
242       std::string( "Library \"" ) +
243       can_name +
244       std::string( "\" not recognized as a cpPlugins library" )
245       );
246
247   } // fi
248   std::string plugins_name = plugins_name_function( );
249
250   // Get loaded filters
251   _TFunction function = ( _TFunction )(
252     cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, "cpPlugins_LoadedFilters" )
253     );
254   if( function == NULL )
255   {
256     cpPlugins::OS::DLLManager::UnLoad( hnd );
257     throw std::runtime_error(
258       std::string( "Library \"" ) +
259       can_name +
260       std::string( "\" not recognized as a cpPlugins library" )
261       );
262
263   } // fi
264   std::string descriptors = function( );
265   std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
266   std::istringstream str( descriptors );
267   TFilters filters;
268   while( str )
269   {
270     std::string value, category, name;
271     str >> value;
272     if( value == "" )
273       continue;
274     std::replace( value.begin( ), value.end( ), ':', ' ' );
275     std::istringstream value_str( value );
276     value_str >> category >> name;
277
278     // Check if the filter has been already loaded
279     bool found = false;
280     auto fIt = this->m_Filters.find( category );
281     if( fIt != this->m_Filters.end( ) )
282       found = fIt->second.find( name ) != fIt->second.end( );
283     if( found )
284     {
285       cpPlugins::OS::DLLManager::UnLoad( hnd );
286       throw std::runtime_error(
287         std::string( "Filter \"" ) +
288         category + std::string( "::" ) + name +
289         std::string( "\" already exists." )
290         );
291
292     } // fi
293
294     // Get filter creator
295     TCreator creator = ( TCreator )(
296       cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, category + "_" + name )
297       );
298     if( creator == NULL )
299     {
300       cpPlugins::OS::DLLManager::UnLoad( hnd );
301       throw std::runtime_error(
302         std::string( "Filter \"" ) +
303         category + std::string( "::" ) + name +
304         std::string( "\" does not have a valid creator." )
305         );
306
307     } // fi
308
309     TCreatorData data;
310     data.PluginName = plugins_name;
311     data.LibraryHandle = hnd;
312     data.Creator = creator;
313     filters[ category ][ name ] = data;
314
315   } // elihw
316
317   // Keep track of all loaded handlers
318   for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
319     for( auto nIt = cIt->second.begin( ); nIt != cIt->second.end( ); ++nIt )
320       this->m_Filters[ cIt->first ][ nIt->first ] = nIt->second;
321   this->m_Plugins[ can_name ] = hnd;
322 }
323
324 // -------------------------------------------------------------------------
325 void cpPlugins::Interface::Plugins::
326 LoadPlugin( const std::string& pname )
327 {
328   std::stringstream fname;
329   fname << cpPlugins_LIB_PREFIX << pname << cpPlugins_LIB_EXT;
330   unsigned int count = 0;
331   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
332   {
333     std::stringstream dir;
334     dir << *i;
335     if( !cpExtensions::IsPathSeparator( i->back( ) ) )
336       dir << cpExtensions_PATH_SEPARATOR;
337     dir << fname.str( );
338     try
339     {
340       this->LoadFile( dir.str( ) );
341     }
342     catch( ... )
343     {
344       count++;
345
346     } // yrt
347
348   } // rof
349
350   // Throw error, if any
351   if( count == this->m_Paths.size( ) )
352     throw std::runtime_error(
353       std::string( "Could not load plugin " ) +
354       std::string( "\"" ) + pname +
355       std::string( "\" from any registered path." )
356       );
357 }
358
359 // -------------------------------------------------------------------------
360 void cpPlugins::Interface::Plugins::
361 LoadDirectory( const std::string& dirname )
362 {
363   DIR* dir;
364   struct dirent* ent;
365   if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
366   {
367     while( ( ent = readdir( dir ) ) != NULL )
368     {
369       try
370       {
371         std::stringstream fname;
372         fname << dirname << cpExtensions_PATH_SEPARATOR << ent->d_name;
373         this->LoadFile( fname.str( ) );
374       }
375       catch( ... ) { }
376
377     } // elihw
378     closedir( dir );
379   }
380   else
381     throw std::runtime_error(
382       std::string( "Could not load directory " ) +
383       std::string( "\"" ) +  dirname + std::string( "\"" )
384       );
385 }
386
387 // -------------------------------------------------------------------------
388 void cpPlugins::Interface::Plugins::
389 GuessPlugins( )
390 {
391   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
392   {
393     try { this->LoadDirectory( *i ); }
394     catch( ... ) { }
395
396   } // rof
397 }
398
399 // -------------------------------------------------------------------------
400 cpPlugins::Interface::Plugins::TProcess::Pointer
401 cpPlugins::Interface::Plugins::
402 CreateProcessObject( const std::string& category, const std::string& name )
403 {
404   typedef cpPlugins::BaseObjects::ProcessObject::Pointer _Ptr;
405   _Ptr o = NULL;
406   auto cIt = this->m_Filters.find( category );
407   if( cIt != this->m_Filters.end( ) )
408   {
409     auto nIt = cIt->second.find( name );
410     if( nIt != cIt->second.end( ) )
411     {
412       o = reinterpret_cast< _Ptr* >( nIt->second.Creator( ) )->GetPointer( );
413       o->SetName( name );
414       o->SetPluginName( nIt->second.PluginName );
415
416     } // fi
417
418   } // fi
419   return( o );
420 }
421
422 // -------------------------------------------------------------------------
423 cpPlugins::Interface::Plugins::
424 Plugins( )
425   : Superclass( )
426 {
427 #ifdef cpPlugins_OS_Windows
428   char* p;
429   size_t size;
430   _dupenv_s( &p, &size, cpPlugins_PATHS );
431 #else // cpPlugins_OS_Windows
432   char* p = std::getenv( cpPlugins_PATHS );
433 #endif // cpPlugins_OS_Windows
434   std::stringstream str;
435   if( p != NULL )
436     str << p << cpPlugins_ENV_SEPARATOR;
437   str << ".";
438   this->OpenEnvironments( str.str( ) );
439
440   // Try to read locally defined paths
441   /* TODO
442      std::vector< std::string > tokens;
443      cpExtensions::Tokenize( tokens, str.str( ), cpPlugins_ENV_SEPARATOR );
444      for( auto t = tokens.begin( ); t != tokens.end( ); ++t )
445      {
446      try
447      {
448      this->OpenEnvironments( *t );
449      }
450      catch( ... ) { }
451
452      } // rof
453   */
454 }
455
456 // -------------------------------------------------------------------------
457 cpPlugins::Interface::Plugins::
458 ~Plugins( )
459 {
460 }
461
462 // -------------------------------------------------------------------------
463 void cpPlugins::Interface::Plugins::
464 PrintSelf( std::ostream& os, itk::Indent indent ) const
465 {
466   // Show data
467   os << indent << "----- PATHS -----" << std::endl;
468   auto paths = this->GetPaths( );
469   for( auto paIt = paths.begin( ); paIt != paths.end( ); ++paIt )
470     os << indent << *paIt << std::endl;
471   os << indent << std::endl << indent << "----- PLUGINS -----" << std::endl;
472   auto plugins = this->GetPlugins( );
473   for( auto plIt = plugins.begin( ); plIt != plugins.end( ); ++plIt )
474     os << indent << *plIt << std::endl;
475   os << indent << std::endl << indent << "----- FILTERS -----" << std::endl;
476   auto categories = this->GetCategories( );
477   for( auto cIt = categories.begin( ); cIt != categories.end( ); ++cIt )
478   {
479     os << indent << "** Category: " << *cIt << " **" << std::endl;
480     auto filters = this->GetFilters( *cIt );
481     for( auto fIt = filters.begin( ); fIt != filters.end( ); ++fIt )
482       os << indent << indent << indent << "Filter: " << *fIt << std::endl;
483
484   } // rof
485
486 }
487
488 // eof - $RCSfile$