]> Creatis software - cpPlugins.git/blob - lib/cpPlugins/Interface.cxx
8ca68322ada90e5a9bb4703b0a024ff344f4603f
[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 config_file;
106     if(
107       cpPlugins::ReadFileIntoBuffer(
108         config_file,
109         cpPlugins::CanonicalPath(
110           dir.str( ) + std::string( cpPlugins_CONFIG )
111           )
112         )
113       )
114     {
115       std::istringstream input( config_file );
116       for( std::string line; std::getline( input, line ); )
117       {
118         std::vector< std::string > tokens;
119         cpPlugins::TokenizeString( tokens, line, "@" );
120         std::string library_file = "";
121         if( tokens[ 0 ] == "local" )
122           library_file =
123             cpPlugins::CanonicalPath(
124               dir.str( ) +
125               std::string( cpPlugins_LIB_PREFIX ) +
126               tokens[ 1 ] +
127               std::string( "." ) + 
128               std::string( cpPlugins_LIB_EXT )
129               );
130         else if( tokens[ 0 ] == "global" )
131           library_file = tokens[ 1 ];
132
133         if( library_file != "" )
134         {
135           std::string error = "";
136           void* hnd = cpPlugins::DLLManager::Load( library_file, error );
137           if( hnd != NULL )
138             this->m_Libraries[ library_file ] = hnd;
139           else
140             all_errors << " ; " << error;
141
142         } // fi
143
144       } // rof
145
146     } // fi
147
148   } // rof
149
150   // Throw errors
151   if( all_errors.str( ) != "" )
152     throw std::runtime_error(
153       std::string( "Loading environment libraries errors: " ) +
154       all_errors.str( )
155       );
156 }
157
158 // -------------------------------------------------------------------------
159 void cpPlugins::Interface::
160 LoadFile( const std::string& fname )
161 {
162   // Resolve canonical filename
163   std::string can_name = cpPlugins::CanonicalPath( fname );
164   if( can_name == "" )
165     throw std::runtime_error(
166       std::string( "Loading file: can't find library \"" ) +
167       fname +
168       std::string( "\"" )
169       );
170   if( this->m_Plugins.find( can_name ) != this->m_Plugins.end( ) )
171     return;
172
173   // Load the library
174   std::string error = "";
175   void* hnd = cpPlugins::DLLManager::Load( can_name, error );
176   if( hnd == NULL )
177     throw std::runtime_error(
178       std::string( "Loading plugin library: " ) + error
179       );
180
181   // Get plugins name
182   typedef const char* ( *_TFunction )( );
183   _TFunction plugins_name_function = ( _TFunction )(
184     cpPlugins::DLLManager::GetFunctionHandle( hnd, "cpPlugins_Name" )
185     );
186   if( plugins_name_function == NULL )
187   {
188     cpPlugins::DLLManager::UnLoad( hnd );
189     throw std::runtime_error(
190       std::string( "Library \"" ) +
191       can_name +
192       std::string( "\" not recognized as a cpPlugins library" )
193       );
194
195   } // fi
196   std::string plugins_name = plugins_name_function( );
197
198   // Get loaded filters
199   _TFunction function = ( _TFunction )(
200     cpPlugins::DLLManager::GetFunctionHandle( hnd, "cpPlugins_LoadedFilters" )
201     );
202   if( function == NULL )
203   {
204     cpPlugins::DLLManager::UnLoad( hnd );
205     throw std::runtime_error(
206       std::string( "Library \"" ) +
207       can_name +
208       std::string( "\" not recognized as a cpPlugins library" )
209       );
210
211   } // fi
212   std::string descriptors = function( );
213   std::replace( descriptors.begin( ), descriptors.end( ), ';', ' ' );
214   std::istringstream str( descriptors );
215   TFilters filters;
216   while( str )
217   {
218     std::string value, category, name;
219     str >> value;
220     if( value == "" )
221       continue;
222     std::replace( value.begin( ), value.end( ), ':', ' ' );
223     std::istringstream value_str( value );
224     value_str >> category >> name;
225
226     // Check if the filter has been already loaded
227     bool found = false;
228     auto fIt = this->m_Filters.find( category );
229     if( fIt != this->m_Filters.end( ) )
230       found = fIt->second.find( name ) != fIt->second.end( );
231     if( found )
232     {
233       cpPlugins::DLLManager::UnLoad( hnd );
234       throw std::runtime_error(
235         std::string( "Filter \"" ) +
236         category + std::string( "::" ) + name +
237         std::string( "\" already exists." )
238         );
239
240     } // fi
241
242     // Get filter creator
243     TCreator creator = ( TCreator )(
244       cpPlugins::DLLManager::GetFunctionHandle( hnd, category + "_" + name )
245       );
246     if( creator == NULL )
247     {
248       cpPlugins::DLLManager::UnLoad( hnd );
249       throw std::runtime_error(
250         std::string( "Filter \"" ) +
251         category + std::string( "::" ) + name +
252         std::string( "\" does not have a valid creator." )
253         );
254
255     } // fi
256
257     TCreatorData data;
258     data.PluginName = plugins_name;
259     data.LibraryHandle = hnd;
260     data.Creator = creator;
261     filters[ category ][ name ] = data;
262
263   } // elihw
264
265   // Keep track of all loaded handlers
266   for( auto cIt = filters.begin( ); cIt != filters.end( ); ++cIt )
267     for( auto nIt = cIt->second.begin( ); nIt != cIt->second.end( ); ++nIt )
268       this->m_Filters[ cIt->first ][ nIt->first ] = nIt->second;
269   this->m_Plugins[ can_name ] = hnd;
270 }
271
272 // -------------------------------------------------------------------------
273 void cpPlugins::Interface::
274 LoadPlugin( const std::string& pname )
275 {
276   std::stringstream fname;
277   fname << cpPlugins_LIB_PREFIX << pname << "." << cpPlugins_LIB_EXT;
278   unsigned int count = 0;
279   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
280   {
281     std::stringstream dir;
282     dir << *i;
283     if( !cpPlugins::IsPathSeparator( i->back( ) ) )
284       dir << cpPlugins_PATH_SEPARATOR;
285     dir << fname.str( );
286     try
287     {
288       this->LoadFile( dir.str( ) );
289     }
290     catch( ... )
291     {
292       count++;
293
294     } // yrt
295
296   } // rof
297
298   // Throw error, if any
299   if( count == this->m_Paths.size( ) )
300     throw std::runtime_error(
301       std::string( "Could not load plugin " ) +
302       std::string( "\"" ) + pname +
303       std::string( "\" from any registered path." )
304       );
305 }
306
307 // -------------------------------------------------------------------------
308 void cpPlugins::Interface::
309 LoadDirectory( const std::string& dirname )
310 {
311   DIR* dir;
312   struct dirent* ent;
313   if( ( dir = opendir( dirname.c_str( ) ) ) != NULL )
314   {
315     while( ( ent = readdir( dir ) ) != NULL )
316     {
317       try
318       {
319         std::stringstream fname;
320         fname << dirname << cpPlugins_PATH_SEPARATOR << ent->d_name;
321         this->LoadFile( fname.str( ) );
322       }
323       catch( ... ) { }
324
325     } // elihw
326     closedir( dir );
327   }
328   else
329     throw std::runtime_error(
330       std::string( "Could not load directory " ) +
331       std::string( "\"" ) +  dirname + std::string( "\"" )
332       );
333 }
334
335 // -------------------------------------------------------------------------
336 void cpPlugins::Interface::
337 GuessPlugins( )
338 {
339   for( auto i = this->m_Paths.begin( ); i != this->m_Paths.end( ); ++i )
340   {
341     try
342     {
343       this->LoadDirectory( *i );
344     }
345     catch( ... )
346     {
347     } // yrt
348
349   } // rof
350 }
351
352 // -------------------------------------------------------------------------
353 cpPlugins::ProcessObject::Pointer cpPlugins::Interface::
354 CreateProcessObject( const std::string& category, const std::string& name )
355 {
356   typedef cpPlugins::ProcessObject::Pointer _Ptr;
357   _Ptr o = NULL;
358   auto cIt = this->m_Filters.find( category );
359   if( cIt != this->m_Filters.end( ) )
360   {
361     auto nIt = cIt->second.find( name );
362     if( nIt != cIt->second.end( ) )
363     {
364       o = reinterpret_cast< _Ptr* >( nIt->second.Creator( ) )->GetPointer( );
365       o->SetName( name );
366       o->SetPluginName( nIt->second.PluginName );
367
368     } // fi
369
370   } // fi
371   return( o );
372 }
373
374 // eof - $RCSfile$