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