]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Interface/Plugins.cxx
Architecture updated.
[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     {
95       if( !cpExtensions::IsPathSeparator( dir.str( ).back( ) ) )
96         dir << cpExtensions_PATH_SEPARATOR;
97       std::stringstream name;
98       name << dir.str( ) << cpPlugins_CONFIG;
99       std::ifstream check( name.str( ).c_str( ), std::ifstream::binary );
100       if( check )
101         this->m_Paths.insert( dir.str( ) );
102       check.close( );
103
104     } // fi
105
106   } // rof
107 }
108
109 // -------------------------------------------------------------------------
110 void cpPlugins::Interface::Plugins::
111 LoadEnvironments( )
112 {
113   std::stringstream all_errors;
114   for( auto d = this->m_Paths.begin( ); d != this->m_Paths.end( ); ++d )
115   {
116     std::stringstream name;
117     name << *d << cpPlugins_CONFIG;
118     std::string buffer;
119     if( cpExtensions::Read( buffer, name.str( ) ) )
120     {
121       std::istringstream input( buffer );
122       for( std::string line; std::getline( input, line ); )
123       {
124         std::vector< std::string > tokens;
125         cpExtensions::Tokenize( tokens, line, "@" );
126         std::string library_file = "";
127         if( tokens[ 0 ] == "local" )
128           library_file =
129             cpExtensions::CanonicalPath(
130               *d + std::string( cpPlugins_LIB_PREFIX ) +
131               tokens[ 1 ] + std::string( cpPlugins_LIB_EXT )
132               );
133         else if( tokens[ 0 ] == "global" )
134           library_file = tokens[ 1 ];
135
136         if( library_file != "" )
137         {
138           std::string error = "";
139           void* hnd = cpPlugins::OS::DLLManager::Load( library_file, error );
140           if( hnd != NULL )
141             this->m_Libraries[ library_file ] = hnd;
142           else
143             all_errors << " ; " << error;
144
145         } // fi
146
147       } // rof
148
149     } // fi
150
151   } // rof
152
153   // Throw errors
154   if( all_errors.str( ) != "" )
155     throw std::runtime_error(
156       std::string( "Loading environment libraries errors: " ) +
157       all_errors.str( )
158       );
159 }
160
161 // -------------------------------------------------------------------------
162 void cpPlugins::Interface::Plugins::
163 SaveEnvironments( const std::string& dir ) const
164 {
165   if( this->m_Paths.size( ) > 0 )
166   {
167     std::stringstream buffer;
168     auto i = this->m_Paths.begin( );
169     for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
170       buffer << *i << std::endl;
171
172     std::stringstream fname;
173     fname << dir;
174     if( !cpExtensions::IsPathSeparator( dir.back( ) ) )
175       fname << cpExtensions_PATH_SEPARATOR;
176     fname << cpPlugins_PATHS;
177     if( !cpExtensions::Write( buffer.str( ), fname.str( ) ) )
178       throw std::runtime_error( "Error writing environment file." );
179   }
180   else
181     throw std::runtime_error( "No paths to save." );
182 }
183
184 // -------------------------------------------------------------------------
185 void cpPlugins::Interface::Plugins::
186 OpenEnvironments( const std::string& dir )
187 {
188   std::stringstream fname;
189   fname << dir;
190   if( !cpExtensions::IsPathSeparator( dir.back( ) ) )
191     fname << cpExtensions_PATH_SEPARATOR;
192   fname << cpPlugins_PATHS;
193   std::string buffer;
194   if( cpExtensions::Read( buffer, fname.str( ) ) )
195   {
196     std::istringstream input( buffer );
197     std::stringstream paths;
198     for( std::string line; std::getline( input, line ); )
199       paths << line << cpPlugins_ENV_SEPARATOR;
200     this->AddEnvironments( paths.str( ) );
201   }
202   else
203     throw std::runtime_error( "Error opening environment file." );
204 }
205
206 // -------------------------------------------------------------------------
207 void cpPlugins::Interface::Plugins::
208 LoadFile( const std::string& fname )
209 {
210   // Resolve canonical filename
211   std::string can_name = cpExtensions::CanonicalPath( fname );
212   if( can_name == "" )
213     throw std::runtime_error(
214       std::string( "Loading file: can't find library \"" ) +
215       fname +
216       std::string( "\"" )
217       );
218   if( this->m_Plugins.find( can_name ) != this->m_Plugins.end( ) )
219     return;
220
221   // Load the library
222   std::string error = "";
223   void* hnd = cpPlugins::OS::DLLManager::Load( can_name, error );
224   if( hnd == NULL )
225     throw std::runtime_error(
226       std::string( "Loading plugin library: " ) + error
227       );
228
229   // Get plugins name
230   typedef const char* ( *_TFunction )( );
231   _TFunction plugins_name_function = ( _TFunction )(
232     cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, "cpPlugins_Name" )
233     );
234   if( plugins_name_function == NULL )
235   {
236     cpPlugins::OS::DLLManager::UnLoad( hnd );
237     throw std::runtime_error(
238       std::string( "Library \"" ) +
239       can_name +
240       std::string( "\" not recognized as a cpPlugins library" )
241       );
242
243   } // fi
244   std::string plugins_name = plugins_name_function( );
245
246   // Get loaded filters
247   _TFunction function = ( _TFunction )(
248     cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, "cpPlugins_LoadedFilters" )
249     );
250   if( function == NULL )
251   {
252     cpPlugins::OS::DLLManager::UnLoad( hnd );
253     throw std::runtime_error(
254       std::string( "Library \"" ) +
255       can_name +
256       std::string( "\" not recognized as a cpPlugins library" )
257       );
258
259   } // fi
260   std::string descriptors = function( );
261   std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
262   std::istringstream str( descriptors );
263   TFilters filters;
264   while( str )
265   {
266     std::string value, category, name;
267     str >> value;
268     if( value == "" )
269       continue;
270     std::replace( value.begin( ), value.end( ), ':', ' ' );
271     std::istringstream value_str( value );
272     value_str >> category >> name;
273
274     // Check if the filter has been already loaded
275     bool found = false;
276     auto fIt = this->m_Filters.find( category );
277     if( fIt != this->m_Filters.end( ) )
278       found = fIt->second.find( name ) != fIt->second.end( );
279     if( found )
280     {
281       cpPlugins::OS::DLLManager::UnLoad( hnd );
282       throw std::runtime_error(
283         std::string( "Filter \"" ) +
284         category + std::string( "::" ) + name +
285         std::string( "\" already exists." )
286         );
287
288     } // fi
289
290     // Get filter creator
291     TCreator creator = ( TCreator )(
292       cpPlugins::OS::DLLManager::GetFunctionHandle( hnd, category + "_" + name )
293       );
294     if( creator == NULL )
295     {
296       cpPlugins::OS::DLLManager::UnLoad( hnd );
297       throw std::runtime_error(
298         std::string( "Filter \"" ) +
299         category + std::string( "::" ) + name +
300         std::string( "\" does not have a valid creator." )
301         );
302
303     } // fi
304
305     TCreatorData data;
306     data.PluginName = plugins_name;
307     data.LibraryHandle = hnd;
308     data.Creator = creator;
309     filters[ category ][ name ] = data;
310
311   } // elihw
312
313   // Keep track of all loaded handlers
314   for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
315     for( auto nIt = cIt->second.begin( ); nIt != cIt->second.end( ); ++nIt )
316       this->m_Filters[ cIt->first ][ nIt->first ] = nIt->second;
317   this->m_Plugins[ can_name ] = hnd;
318 }
319
320 // -------------------------------------------------------------------------
321 void cpPlugins::Interface::Plugins::
322 LoadPlugin( const std::string& pname )
323 {
324   std::stringstream fname;
325   fname << cpPlugins_LIB_PREFIX << pname << cpPlugins_LIB_EXT;
326   unsigned int count = 0;
327   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
328   {
329     std::stringstream dir;
330     dir << *i;
331     if( !cpExtensions::IsPathSeparator( i->back( ) ) )
332       dir << cpExtensions_PATH_SEPARATOR;
333     dir << fname.str( );
334     try
335     {
336       this->LoadFile( dir.str( ) );
337     }
338     catch( ... )
339     {
340       count++;
341
342     } // yrt
343
344   } // rof
345
346   // Throw error, if any
347   if( count == this->m_Paths.size( ) )
348     throw std::runtime_error(
349       std::string( "Could not load plugin " ) +
350       std::string( "\"" ) + pname +
351       std::string( "\" from any registered path." )
352       );
353 }
354
355 // -------------------------------------------------------------------------
356 void cpPlugins::Interface::Plugins::
357 LoadDirectory( const std::string& dirname )
358 {
359   DIR* dir;
360   struct dirent* ent;
361   if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
362   {
363     while( ( ent = readdir( dir ) ) != NULL )
364     {
365       try
366       {
367         std::stringstream fname;
368         fname << dirname << cpExtensions_PATH_SEPARATOR << ent->d_name;
369         this->LoadFile( fname.str( ) );
370       }
371       catch( ... ) { }
372
373     } // elihw
374     closedir( dir );
375   }
376   else
377     throw std::runtime_error(
378       std::string( "Could not load directory " ) +
379       std::string( "\"" ) +  dirname + std::string( "\"" )
380       );
381 }
382
383 // -------------------------------------------------------------------------
384 void cpPlugins::Interface::Plugins::
385 GuessPlugins( )
386 {
387   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
388   {
389     try { this->LoadDirectory( *i ); }
390     catch( ... ) { }
391
392   } // rof
393 }
394
395 // -------------------------------------------------------------------------
396 cpPlugins::Interface::Plugins::TProcess::Pointer
397 cpPlugins::Interface::Plugins::
398 CreateProcessObject( const std::string& category, const std::string& name )
399 {
400   typedef cpPlugins::BaseObjects::ProcessObject::Pointer _Ptr;
401   _Ptr o = NULL;
402   auto cIt = this->m_Filters.find( category );
403   if( cIt != this->m_Filters.end( ) )
404   {
405     auto nIt = cIt->second.find( name );
406     if( nIt != cIt->second.end( ) )
407     {
408       o = reinterpret_cast< _Ptr* >( nIt->second.Creator( ) )->GetPointer( );
409       o->SetName( name );
410       o->SetPluginName( nIt->second.PluginName );
411
412     } // fi
413
414   } // fi
415   return( o );
416 }
417
418 // -------------------------------------------------------------------------
419 cpPlugins::Interface::Plugins::
420 Plugins( )
421   : Superclass( )
422 {
423   char* p = std::getenv( cpPlugins_PATHS );
424   std::stringstream str;
425   if( p != NULL )
426     str << p << cpPlugins_ENV_SEPARATOR;
427   str << ".";
428   this->AddEnvironments( str.str( ) );
429 }
430
431 // -------------------------------------------------------------------------
432 cpPlugins::Interface::Plugins::
433 ~Plugins( )
434 {
435 }
436
437 // -------------------------------------------------------------------------
438 void cpPlugins::Interface::Plugins::
439 PrintSelf( std::ostream& os, itk::Indent indent ) const
440 {
441   // Show data
442   os << indent << "----- PATHS -----" << std::endl;
443   auto paths = this->GetPaths( );
444   for( auto paIt = paths.begin( ); paIt != paths.end( ); ++paIt )
445     os << indent << *paIt << std::endl;
446   os << indent << std::endl << indent << "----- PLUGINS -----" << std::endl;
447   auto plugins = this->GetPlugins( );
448   for( auto plIt = plugins.begin( ); plIt != plugins.end( ); ++plIt )
449     os << indent << *plIt << std::endl;
450   os << indent << std::endl << indent << "----- FILTERS -----" << std::endl;
451   auto categories = this->GetCategories( );
452   for( auto cIt = categories.begin( ); cIt != categories.end( ); ++cIt )
453   {
454     os << indent << "** Category: " << *cIt << " **" << std::endl;
455     auto filters = this->GetFilters( *cIt );
456     for( auto fIt = filters.begin( ); fIt != filters.end( ); ++fIt )
457       os << indent << indent << indent << "Filter: " << *fIt << std::endl;
458
459   } // rof
460
461 }
462
463 // eof - $RCSfile$