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