]> SALOME platform Git repositories - modules/kernel.git/blob - src/Container/Container_i.cxx
Salome HOME
CCAR: improvement to the component loading mechanism of SALOME (issue 20675)
[modules/kernel.git] / src / Container / Container_i.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  SALOME Container : implementation of container and engine for Kernel
23 //  File   : Container_i.cxx
24 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA 
25 //  Module : SALOME
26 //  $Header$
27 //#define private public
28 //
29 #include <string.h>
30 #include <stdio.h>
31 #include <time.h>
32 #include <sys/types.h>
33 #ifndef WIN32
34 #include <sys/time.h>
35 #include <dlfcn.h>
36 #include <unistd.h>
37 #include <sys/wait.h>
38 #else
39 #include <signal.h>
40 #include <process.h>
41 #include <direct.h>
42 int SIGUSR1 = 1000;
43 #endif
44
45 #include "utilities.h"
46 #include <SALOMEconfig.h>
47 #include CORBA_SERVER_HEADER(SALOME_Component)
48 #include CORBA_SERVER_HEADER(SALOME_Exception)
49 #include <pthread.h>  // must be before Python.h !
50 #include "SALOME_Container_i.hxx"
51 #include "SALOME_Component_i.hxx"
52 #include "SALOME_FileRef_i.hxx"
53 #include "SALOME_FileTransfer_i.hxx"
54 #include "Salome_file_i.hxx"
55 #include "SALOME_NamingService.hxx"
56 #include "Basics_Utils.hxx"
57
58 #include <Python.h>
59 #include "Container_init_python.hxx"
60
61 using namespace std;
62
63 bool _Sleeping = false ;
64
65 // // Needed by multi-threaded Python --- Supervision
66 int _ArgC ;
67 char ** _ArgV ;
68
69 extern "C" {void ActSigIntHandler() ; }
70 #ifndef WIN32
71 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
72 #else
73 extern "C" {void SigIntHandler( int ) ; }
74 #endif
75
76 #ifndef WIN32
77 #define LIB "lib"
78 #define ENGINESO "Engine.so"
79 #else
80 #define LIB ""
81 #define ENGINESO "Engine.dll"
82 #endif
83
84 #ifdef WIN32
85 #define SEP ';'
86 #define SLASH '\\'
87 #else
88 #define SEP ':'
89 #define SLASH '/'
90 #endif
91
92 map<std::string, int> Engines_Container_i::_cntInstances_map;
93 map<std::string, void *> Engines_Container_i::_library_map;
94 map<std::string, void *> Engines_Container_i::_toRemove_map;
95 omni_mutex Engines_Container_i::_numInstanceMutex ;
96
97 static PyObject* _pyCont;
98
99 int checkifexecutable(const std::string&);
100 int findpathof(const std::string& path, std::string&, const std::string&);
101
102 /*! \class Engines_Container_i
103  *  \brief C++ implementation of Engines::Container interface
104  *
105  */
106
107
108 //=============================================================================
109 /*! 
110 *  Default constructor, not for use
111 */
112 //=============================================================================
113
114 Engines_Container_i::Engines_Container_i () :
115 _numInstance(0),_id(0),_NS(0)
116 {
117 }
118
119 //=============================================================================
120 /*! 
121 *  Construtor to use
122 */
123 //=============================================================================
124
125 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
126                                           PortableServer::POA_ptr poa,
127                                           char *containerName ,
128                                           int argc , char* argv[],
129                                           bool activAndRegist,
130                                           bool isServantAloneInProcess
131                                           ) :
132   _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess),_id(0),_NS(0)
133 {
134   _pid = (long)getpid();
135
136   if(activAndRegist)
137     ActSigIntHandler() ;
138
139   _argc = argc ;
140   _argv = argv ;
141
142   string hostname = Kernel_Utils::GetHostname();
143 #ifndef WIN32
144   MESSAGE(hostname << " " << getpid() << 
145     " Engines_Container_i starting argc " <<
146     _argc << " Thread " << pthread_self() ) ;
147 #else
148   MESSAGE(hostname << " " << _getpid() << 
149     " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
150 #endif
151
152   int i = 0 ;
153   while ( _argv[ i ] )
154   {
155     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
156     i++ ;
157   }
158
159   if ( argc < 2 )
160   {
161     INFOS("SALOME_Container usage : SALOME_Container ServerName");
162     ASSERT(0) ;
163   }
164   SCRUTE(argv[1]);
165   _isSupervContainer = false;
166
167   _orb = CORBA::ORB::_duplicate(orb) ;
168   _poa = PortableServer::POA::_duplicate(poa) ;
169
170   // Pour les containers paralleles: il ne faut pas enregistrer et activer
171   // le container generique, mais le container specialise
172
173   if(activAndRegist)
174   {
175     _id = _poa->activate_object(this);
176     _NS = new SALOME_NamingService();
177     _NS->init_orb( _orb ) ;
178     CORBA::Object_var obj=_poa->id_to_reference(*_id);
179     Engines::Container_var pCont 
180       = Engines::Container::_narrow(obj);
181     _remove_ref();
182
183     _containerName = _NS->BuildContainerNameForNS(containerName,
184       hostname.c_str());
185     SCRUTE(_containerName);
186     _NS->Register(pCont, _containerName.c_str());
187     MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
188       << _containerName);
189
190     // Python: 
191     // import SALOME_Container
192     // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
193
194     CORBA::String_var sior =  _orb->object_to_string(pCont);
195     string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
196     myCommand += _containerName + "','";
197     myCommand += sior;
198     myCommand += "')\n";
199     SCRUTE(myCommand);
200
201     PyGILState_STATE gstate = PyGILState_Ensure();
202
203 #ifdef WIN32
204     // mpv: this is temporary solution: there is a unregular crash if not
205     //Sleep(2000);
206     //
207     // first element is the path to Registry.dll, but it's wrong
208     PyRun_SimpleString("import sys\n");
209     PyRun_SimpleString("sys.path = sys.path[1:]\n");
210 #endif
211     PyRun_SimpleString("import SALOME_Container\n");
212     PyRun_SimpleString((char*)myCommand.c_str());
213     PyObject *mainmod = PyImport_AddModule("__main__");
214     PyObject *globals = PyModule_GetDict(mainmod);
215     _pyCont = PyDict_GetItemString(globals, "pyCont");
216
217     PyGILState_Release(gstate);
218
219     fileTransfer_i* aFileTransfer = new fileTransfer_i();
220     CORBA::Object_var obref=aFileTransfer->_this();
221     _fileTransfer = Engines::fileTransfer::_narrow(obref);
222     aFileTransfer->_remove_ref();
223   }
224 }
225
226 //=============================================================================
227 /*! 
228 *  Destructor
229 */
230 //=============================================================================
231
232 Engines_Container_i::~Engines_Container_i()
233 {
234   MESSAGE("Container_i::~Container_i()");
235   if(_id)
236     delete _id;
237   if(_NS)
238     delete _NS;
239 }
240
241 //=============================================================================
242 //! Get container name
243 /*! 
244 *  CORBA attribute: Container name (see constructor)
245 */
246 //=============================================================================
247
248 char* Engines_Container_i::name()
249 {
250   return CORBA::string_dup(_containerName.c_str()) ;
251 }
252
253 //=============================================================================
254 //! Get container working directory
255 /*! 
256 *  CORBA attribute: Container working directory 
257 */
258 //=============================================================================
259
260 char* Engines_Container_i::workingdir()
261 {
262   char wd[256];
263   getcwd (wd,256);
264   return CORBA::string_dup(wd) ;
265 }
266
267 //=============================================================================
268 //! Get container log file name
269 /*! 
270 *  CORBA attribute: Container log file name
271 */
272 //=============================================================================
273
274 char* Engines_Container_i::logfilename()
275 {
276   return CORBA::string_dup(_logfilename.c_str()) ;
277 }
278
279 //! Set container log file name
280 void Engines_Container_i::logfilename(const char* name)
281 {
282   _logfilename=name;
283 }
284
285 //=============================================================================
286 //! Get container host name
287 /*! 
288 *  CORBA method: Get the hostName of the Container (without domain extensions)
289 */
290 //=============================================================================
291
292 char* Engines_Container_i::getHostName()
293 {
294   string s = Kernel_Utils::GetHostname();
295   //  MESSAGE("Engines_Container_i::getHostName " << s);
296   return CORBA::string_dup(s.c_str()) ;
297 }
298
299 //=============================================================================
300 //! Get container PID
301 /*! 
302 *  CORBA method: Get the PID (process identification) of the Container
303 */
304 //=============================================================================
305
306 CORBA::Long Engines_Container_i::getPID()
307 {
308   return (CORBA::Long)getpid();
309 }
310
311 //=============================================================================
312 //! Ping the servant to check it is still alive
313 /*! 
314 *  CORBA method: check if servant is still alive
315 */
316 //=============================================================================
317 void Engines_Container_i::ping()
318 {
319   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
320 }
321
322 //=============================================================================
323 //! Shutdown the container
324 /*! 
325 *  CORBA method, oneway: Server shutdown. 
326 *  - Container name removed from naming service,
327 *  - servant deactivation,
328 *  - orb shutdown if no other servants in the process 
329 */
330 //=============================================================================
331 void Engines_Container_i::Shutdown()
332 {
333   MESSAGE("Engines_Container_i::Shutdown()");
334
335   /* For each component contained in this container
336   * tell it to self-destroy
337   */
338   std::map<std::string, Engines::Component_var>::iterator itm;
339   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
340     {
341       try
342         {
343           itm->second->destroy();
344         }
345       catch(const CORBA::Exception& e)
346         {
347           // ignore this entry and continue
348         }
349       catch(...)
350         {
351           // ignore this entry and continue
352         }
353     }
354   _listInstances_map.clear();
355
356   _NS->Destroy_FullDirectory(_containerName.c_str());
357   _NS->Destroy_Name(_containerName.c_str());
358   if(_isServantAloneInProcess)
359   {
360     MESSAGE("Effective Shutdown of container Begins...");
361     if(!CORBA::is_nil(_orb))
362       _orb->shutdown(0);
363   }
364 }
365
366 //=============================================================================
367 //! load a component implementation
368 /*! 
369 *  CORBA method
370 *  \param componentName         component name
371 *  \param reason                explains error when load fails
372 *  \return true if dlopen successfull or already done, false otherwise
373 */
374 //=============================================================================
375 bool
376 Engines_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
377 {
378
379   //=================================================================
380   // --- C++ implementation section 
381   //=================================================================
382   std::string retso;
383   if(load_component_CppImplementation(componentName,retso))
384     {
385       reason=CORBA::string_dup("");
386       return true;
387     }
388   else if(retso != "ImplementationNotFound")
389     {
390       reason=CORBA::string_dup(retso.c_str());
391       return false;
392     }
393
394   retso="Component ";
395   retso+=componentName;
396   retso+=": Can't find C++ implementation ";
397   retso+=string(LIB) + componentName + ENGINESO;
398
399   //=================================================================
400   // --- Python implementation section 
401   //=================================================================
402   std::string retpy;
403   if(load_component_PythonImplementation(componentName,retpy))
404     {
405       reason=CORBA::string_dup("");
406       return true;
407     }
408   else if(retpy != "ImplementationNotFound")
409     {
410       reason=CORBA::string_dup(retpy.c_str());
411       return false;
412     }
413   
414   retpy="Component ";
415   retpy+=componentName;
416   retpy+=": Can't find python implementation ";
417   retpy+=componentName;
418   retpy+="(.py)";
419
420   //=================================================================
421   // -- Executable implementation section
422   //=================================================================
423   std::string retex;
424   if(load_component_ExecutableImplementation(componentName,retex))
425     {
426       reason=CORBA::string_dup("");
427       return true;
428     }
429   else if(retex != "ImplementationNotFound")
430     {
431       reason=CORBA::string_dup(retex.c_str());
432       return false;
433     }
434
435   retex="Component ";
436   retex+=componentName;
437   retex+=": Can't find executable implementation ";
438   retex+=componentName;
439   retex+=".exe";
440
441   std::string ret="Component implementation not found: ";
442   ret += componentName ;
443   ret += '\n' ;
444   ret += retso+ '\n' ;
445   ret += retpy+ '\n' ;
446   ret += retex+ '\n' ;
447
448   std::cerr << ret << std::endl;
449   reason=CORBA::string_dup(ret.c_str());
450
451   return false;
452 }
453
454 //=============================================================================
455 //! try to load a C++ component implementation
456 /*! 
457 *  C++ method: 
458 *  \param componentName      the name of the component (COMPONENT, for example)
459 *  \param reason             explains error when load fails
460 *  \return true if loading is successfull or already done, false otherwise
461 */
462 //=============================================================================
463 bool
464 Engines_Container_i::load_component_CppImplementation(const char* componentName, std::string& reason)
465 {
466   std::string aCompName(componentName);
467   string impl_name = string(LIB) + aCompName + ENGINESO;
468   SCRUTE(impl_name);
469
470   _numInstanceMutex.lock(); // lock to be alone
471   // (see decInstanceCnt, finalize_removal))
472   if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
473   if (_library_map.count(impl_name) != 0)
474     {
475       MESSAGE("Library " << impl_name << " already loaded");
476       _numInstanceMutex.unlock();
477       reason="";
478       return true;
479     }
480   _numInstanceMutex.unlock();
481
482 #ifndef WIN32
483   void* handle;
484   handle = dlopen( impl_name.c_str() , RTLD_NOW ) ;
485   if ( !handle )
486     {
487       //not loadable. Try to find the lib file in LD_LIBRARY_PATH
488       std::string path;
489       char* p=getenv("LD_LIBRARY_PATH");
490       if(p)path=p;
491       path=path+SEP+"/usr/lib"+SEP+"/lib";
492
493       std::string pth;
494       if(findpathof(path, pth, impl_name))
495         {
496           //found but not loadable
497           reason="Component ";
498           reason+=aCompName;
499           reason+=": C++ implementation found ";
500           reason+=pth;
501           reason+=" but it is not loadable. Error:\n";
502           reason+=dlerror();
503           std::cerr << reason << std::endl;
504           return false;
505         }
506       else
507         {
508           //not found
509           //continue with other implementation
510           reason="ImplementationNotFound";
511           return false;
512         }
513     }
514 #else
515   HINSTANCE handle;
516   handle = LoadLibrary( impl_name.c_str() );
517 #endif
518
519   if ( handle )
520     {
521       _numInstanceMutex.lock();
522       _library_map[impl_name] = handle;
523       _numInstanceMutex.unlock();
524       reason="";
525       return true;
526     }
527
528   return false;
529
530 }
531 //=============================================================================
532 //! try to load a Python component implementation
533 /*! 
534 *  C++ method: 
535 *  \param componentName         name of the component
536 *  \param reason                explains error when load fails
537 *  \return true if loading is successfull or already done, false otherwise
538 */
539 //=============================================================================
540 bool
541 Engines_Container_i::load_component_PythonImplementation(const char* componentName, std::string& reason)
542 {
543   std::string aCompName(componentName);
544
545   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
546   if (_library_map.count(aCompName) != 0)
547     {
548       _numInstanceMutex.unlock() ;
549       reason="";
550       return true; // Python Component, already imported
551     }
552   _numInstanceMutex.unlock() ;
553
554   PyGILState_STATE gstate = PyGILState_Ensure();
555   PyObject *result = PyObject_CallMethod(_pyCont,
556                                          (char*)"import_component",
557                                          (char*)"s",componentName);
558
559   reason=PyString_AsString(result);
560   Py_XDECREF(result);
561   SCRUTE(reason);
562   PyGILState_Release(gstate);
563
564   if (reason=="")
565     {
566       //Python component has been loaded (import componentName)
567       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
568       _library_map[aCompName] = (void *)_pyCont; // any non O value OK
569       _numInstanceMutex.unlock() ;
570       MESSAGE("import Python: "<< aCompName <<" OK");
571       return true;
572     }
573   else if(reason=="ImplementationNotFound")
574     {
575       //Python implementation has not been found. Continue with other implementation
576       reason="ImplementationNotFound";
577     }
578   else
579     {
580       //Python implementation has been found but loading has failed
581       std::cerr << reason << std::endl;
582     }
583   return false;
584
585 }
586 //=============================================================================
587 //! try to load a Executable component implementation
588 /*! 
589 *  C++ method: 
590 *  \param componentName        name of the component
591 *  \param reason               explains error when load fails
592 *  \return true if loading is successfull or already done, false otherwise
593 */
594 //=============================================================================
595 bool
596 Engines_Container_i::load_component_ExecutableImplementation(const char* componentName, std::string& reason)
597 {
598   std::string aCompName(componentName);
599   std::string executable=aCompName+".exe";
600
601   std::string path;
602   std::string pth;
603
604   char* p=getenv("PATH");
605   if(p)path=p;
606
607   if (findpathof(path, pth, executable))
608     {
609       if(checkifexecutable(pth))
610         {
611           _numInstanceMutex.lock() ; // lock to be alone (stl container write)
612           _library_map[executable] = (void *)1; // any non O value OK
613           _numInstanceMutex.unlock() ;
614           MESSAGE("import executable: "<< pth <<" OK");
615           reason="";
616           return true;
617         }
618       reason="Component ";
619       reason+=aCompName;
620       reason+=": implementation found ";
621       reason+=pth;
622       reason+=" but it is not executable";
623       std::cerr << reason << std::endl;
624     }
625   else
626     {
627       reason="ImplementationNotFound";
628     }
629   return false;
630 }
631
632 //=============================================================================
633 //! Create a new component instance
634 /*! 
635 *  CORBA method: Creates a new servant instance of a component.
636 *  The servant registers itself to naming service and Registry.
637 *  \param genericRegisterName  Name of the component instance to register
638 *                         in Registry & Name Service (without _inst_n suffix)
639 *  \param studyId         0 for multiStudy instance, 
640 *                         study Id (>0) otherwise
641 *  \return a loaded component
642 */
643 //=============================================================================
644 Engines::Component_ptr
645 Engines_Container_i::create_component_instance(const char*genericRegisterName,
646                                                CORBA::Long studyId)
647 {
648   Engines::FieldsDict_var env = new Engines::FieldsDict;
649   char* reason;
650   Engines::Component_ptr compo = create_component_instance_env(genericRegisterName, studyId, env, reason);
651   CORBA::string_free(reason);
652   return compo;
653 }
654
655 //=============================================================================
656 //! Create a new component instance with environment variables specified
657 /*! 
658 *  CORBA method: Creates a new servant instance of a component.
659 *  The servant registers itself to naming service and Registry.
660 *  \param genericRegisterName  Name of the component instance to register
661 *                         in Registry & Name Service (without _inst_n suffix)
662 *  \param studyId         0 for multiStudy instance, 
663 *                         study Id (>0) otherwise
664 *  \param env             dict of env variables
665 *  \param reason          explains error when create_component_instance_env fails
666 *  \return a loaded component
667 */
668 //=============================================================================
669 Engines::Component_ptr
670 Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
671                                                    CORBA::Long studyId,
672                                                    const Engines::FieldsDict& env,
673                                                    CORBA::String_out reason)
674 {
675   if (studyId < 0)
676     {
677       INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
678       reason=CORBA::string_dup("studyId must be > 0 for mono study instance, =0 for multiStudy");
679       return Engines::Component::_nil() ;
680     }
681
682   std::string error;
683   if (_library_map.count(genericRegisterName) != 0)
684     {
685       // It's a Python component
686       Engines::Component_ptr compo = createPythonInstance(genericRegisterName, studyId, error);
687       reason=CORBA::string_dup(error.c_str());
688       return compo;
689     }
690
691   string impl_name = string(LIB) + genericRegisterName + ENGINESO;
692   if (_library_map.count(impl_name) != 0)
693     {
694       // It's a C++ component
695       void* handle = _library_map[impl_name];
696       Engines::Component_ptr compo = createInstance(genericRegisterName, handle, studyId, error);
697       reason=CORBA::string_dup(error.c_str());
698       return compo;
699     }
700
701   impl_name = string(genericRegisterName) + ".exe";
702   if (_library_map.count(impl_name) != 0)
703     {
704       //It's an executable component
705       Engines::Component_ptr compo = createExecutableInstance(genericRegisterName, studyId, env, error);
706       reason=CORBA::string_dup(error.c_str());
707       return compo;
708     }
709
710   error="load_component_Library has probably not been called for component: ";
711   error += genericRegisterName;
712   INFOS(error);
713   reason=CORBA::string_dup(error.c_str());
714   return Engines::Component::_nil() ;
715 }
716
717 //=============================================================================
718 //! Create a new component instance (Executable implementation)
719 /*! 
720 *  \param CompName               Name of the component instance
721 *  \param studyId                0 for multiStudy instance, 
722 *                                study Id (>0) otherwise
723 *  \param env                    dict of env variables
724 *  \param reason                 explains error when creation fails
725 *  \return a loaded component
726 *
727 *   This component is implemented in an executable with name genericRegisterName.exe
728 *   It must register itself in Naming Service. The container waits some time (10 s max)
729 *   it's registration.
730 */
731 //=============================================================================
732 Engines::Component_ptr
733 Engines_Container_i::createExecutableInstance(std::string CompName, int studyId,
734                                               const Engines::FieldsDict& env,
735                                               std::string& reason)
736 {
737   Engines::Component_var iobject = Engines::Component::_nil() ;
738
739   _numInstanceMutex.lock() ; // lock on the instance number
740   _numInstance++ ;
741   int numInstance = _numInstance ;
742   _numInstanceMutex.unlock() ;
743
744   char aNumI[12];
745   sprintf( aNumI , "%d" , numInstance ) ;
746   string instanceName = CompName + "_inst_" + aNumI ;
747   string component_registerName = _containerName + "/" + instanceName;
748
749   //check if an entry exist in naming service
750   CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
751   if ( !CORBA::is_nil(nsobj) )
752   {
753     // unregister the registered component
754     _NS->Destroy_Name(component_registerName.c_str());
755     //kill or shutdown it ???
756   }
757
758   // first arg container ior string
759   // second arg container name
760   // third arg instance name
761
762   Engines::Container_var pCont= _this();
763   CORBA::String_var sior =  _orb->object_to_string(pCont);
764
765   std::string command;
766   command="mkdir -p ";
767   command+=instanceName;
768   command+=";cd ";
769   command+=instanceName;
770   command+=";";
771   command+=CompName ;
772   command+=".exe";
773   command+=" ";
774   command+= sior; // container ior string
775   command+=" ";
776   command+=_containerName; //container name
777   command+=" ";
778   command+=instanceName; //instance name
779   command+=" &";
780   MESSAGE("SALOME_Container::create_component_instance command=" << command);
781
782 #ifndef WIN32
783   // use fork/execl instead of system to get finer control on env variables
784   int status;
785   pid_t pid = fork();
786   if(pid == 0) // child
787     {
788       for (CORBA::ULong i=0; i < env.length(); i++)
789         {
790           if (env[i].value.type()->kind() == CORBA::tk_string)
791             {
792               const char* value;
793               env[i].value >>= value;
794               std::string s(env[i].key);
795               s+='=';
796               s+=value;
797               putenv(strdup(s.c_str()));
798             }
799         }
800
801       execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
802       status=-1;
803     }
804   else if(pid < 0)       // failed to fork
805     {
806       status=-1;
807     }
808   else            //parent
809     {
810       pid_t tpid;
811       do
812         {
813           tpid = wait(&status);
814         } while (tpid != pid);
815     }
816 #else
817   // launch component with a system call
818   int status=system(command.c_str());
819 #endif
820
821   if (status == -1)
822   {
823     reason="SALOME_Container::create_component_instance system failed (system command status -1)";
824     MESSAGE(reason);
825     return Engines::Component::_nil();
826   }
827 #ifndef WIN32
828   else if (WEXITSTATUS(status) == 217)
829   {
830     reason="SALOME_Container::create_component_instance system failed (system command status 217)";
831     MESSAGE(reason);
832     return Engines::Component::_nil();
833   }
834 #endif
835   else
836   {
837     int count=20;
838     CORBA::Object_var obj = CORBA::Object::_nil() ;
839     while ( CORBA::is_nil(obj) && count )
840     {
841 #ifndef WIN32
842       sleep( 1 ) ;
843 #else
844       Sleep(1000);
845 #endif
846       count-- ;
847       MESSAGE( count << ". Waiting for component " << CompName);
848       obj = _NS->Resolve(component_registerName.c_str());
849     }
850
851     if(CORBA::is_nil(obj))
852     {
853       reason="SALOME_Container::create_component_instance failed";
854       MESSAGE(reason);
855       return Engines::Component::_nil();
856     }
857     else
858     {
859       MESSAGE("SALOME_Container::create_component_instance successful");
860       iobject=Engines::Component::_narrow(obj);
861       _listInstances_map[instanceName] = iobject;
862       return iobject._retn();
863     }
864   }
865 }
866
867
868 //=============================================================================
869 //! Create a new component instance (Python implementation)
870 /*! 
871 *  \param CompName               Name of the component instance
872 *  \param studyId                0 for multiStudy instance, 
873 *                                study Id (>0) otherwise
874 *  \param reason                 explains error when creation fails
875 *  \return a loaded component
876 */
877 //=============================================================================
878 Engines::Component_ptr
879 Engines_Container_i::createPythonInstance(std::string CompName, int studyId,
880                                           std::string& reason)
881 {
882   Engines::Component_var iobject = Engines::Component::_nil() ;
883
884   _numInstanceMutex.lock() ; // lock on the instance number
885   _numInstance++ ;
886   int numInstance = _numInstance ;
887   _numInstanceMutex.unlock() ;
888
889   char aNumI[12];
890   sprintf( aNumI , "%d" , numInstance ) ;
891   string instanceName = CompName + "_inst_" + aNumI ;
892   string component_registerName = _containerName + "/" + instanceName;
893
894   PyGILState_STATE gstate = PyGILState_Ensure();
895   PyObject *result = PyObject_CallMethod(_pyCont,
896                                          (char*)"create_component_instance",
897                                          (char*)"ssl",
898                                          CompName.c_str(),
899                                          instanceName.c_str(),
900                                          studyId);
901   const char *ior;
902   const char *error;
903   PyArg_ParseTuple(result,"ss", &ior, &error);
904   string iors = ior;
905   reason=error;
906   Py_DECREF(result);
907   PyGILState_Release(gstate);
908
909   if( iors!="" )
910     {
911       CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
912       iobject = Engines::Component::_narrow( obj ) ;
913       _listInstances_map[instanceName] = iobject;
914     }
915   return iobject._retn();
916 }
917
918 //=============================================================================
919 //! Create a new component instance (C++ implementation)
920 /*! 
921 *  C++ method: create a servant instance of a component.
922 *  \param genericRegisterName    Name of the component instance to register
923 *                                in Registry & Name Service,
924 *                                (without _inst_n suffix, like "COMPONENT")
925 *  \param handle                 loaded library handle
926 *  \param studyId                0 for multiStudy instance, 
927 *                                study Id (>0) otherwise
928 *  \param reason                 explains error when creation fails
929 *  \return a loaded component
930
931 *  example with names:
932 *    - aGenRegisterName = COMPONENT (= first argument)
933 *    - _containerName = /Containers/cli76ce/FactoryServer
934 *    - factoryName = COMPONENTEngine_factory
935 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
936 *    - instanceName = COMPONENT_inst_1
937 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
938 */
939 //=============================================================================
940 Engines::Component_ptr
941 Engines_Container_i::createInstance(std::string genericRegisterName,
942                                     void *handle,
943                                     int studyId,
944                                     std::string& reason)
945 {
946   // --- find the factory
947
948   string aGenRegisterName = genericRegisterName;
949   string factory_name = aGenRegisterName + string("Engine_factory");
950   SCRUTE(factory_name) ;
951
952   typedef PortableServer::ObjectId* (*FACTORY_FUNCTION) (CORBA::ORB_ptr,
953                                                          PortableServer::POA_ptr, 
954                                                          PortableServer::ObjectId *, 
955                                                          const char *, 
956                                                          const char *) ;
957
958 #ifndef WIN32
959   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
960 #else
961   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
962 #endif
963
964   if ( !Component_factory )
965   {
966     INFOS( "Can't resolve symbol: " + factory_name );
967 #ifndef WIN32
968     reason=dlerror();
969     INFOS(reason);
970 #endif
971     return Engines::Component::_nil() ;
972   }
973
974   // --- create instance
975
976   Engines::Component_var iobject = Engines::Component::_nil() ;
977
978   try
979   {
980     _numInstanceMutex.lock() ; // lock on the instance number
981     _numInstance++ ;
982     int numInstance = _numInstance ;
983     _numInstanceMutex.unlock() ;
984
985     char aNumI[12];
986     sprintf( aNumI , "%d" , numInstance ) ;
987     string instanceName = aGenRegisterName + "_inst_" + aNumI ;
988     string component_registerName =
989       _containerName + "/" + instanceName;
990
991     // --- Instanciate required CORBA object
992
993     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
994     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
995                                                 aGenRegisterName.c_str() ) ;
996     if (id == NULL)
997       {
998         reason="Can't get ObjectId from factory";
999         INFOS(reason);
1000         return iobject._retn();
1001       }
1002
1003     // --- get reference & servant from id
1004
1005     CORBA::Object_var obj = _poa->id_to_reference(*id);
1006     iobject = Engines::Component::_narrow( obj ) ;
1007
1008     Engines_Component_i *servant =
1009       dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
1010     ASSERT(servant);
1011     //SCRUTE(servant->_refcount_value());
1012     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1013     _listInstances_map[instanceName] = iobject;
1014     _cntInstances_map[aGenRegisterName] += 1;
1015     _numInstanceMutex.unlock() ;
1016     SCRUTE(aGenRegisterName);
1017     SCRUTE(_cntInstances_map[aGenRegisterName]);
1018     servant->setStudyId(studyId);
1019     servant->_remove_ref(); // do not need servant any more (remove ref from reference_to_servant)
1020     //SCRUTE(servant->_refcount_value());
1021
1022     // --- register the engine under the name
1023     //     containerName(.dir)/instanceName(.object)
1024
1025     _NS->Register( iobject , component_registerName.c_str() ) ;
1026     MESSAGE( component_registerName.c_str() << " bound" ) ;
1027   }
1028   catch (...)
1029   {
1030     reason="Container_i::createInstance exception catched";
1031     INFOS(reason) ;
1032   }
1033   return iobject._retn();
1034 }
1035
1036 //=============================================================================
1037 //! Find an existing (in the container) component instance
1038 /*!
1039 *  CORBA method: Finds a servant instance of a component
1040 *  \param registeredName  Name of the component in Registry or Name Service,
1041 *                         without instance suffix number
1042 *  \param studyId         0 if instance is not associated to a study,
1043 *                         >0 otherwise (== study id)
1044 *  \return the first instance found with same studyId
1045 */
1046 //=============================================================================
1047 Engines::Component_ptr
1048 Engines_Container_i::find_component_instance( const char* registeredName,
1049                                               CORBA::Long studyId)
1050 {
1051   Engines::Component_var anEngine = Engines::Component::_nil();
1052   map<string,Engines::Component_var>::iterator itm =_listInstances_map.begin();
1053   while (itm != _listInstances_map.end())
1054   {
1055     string instance = (*itm).first;
1056     SCRUTE(instance);
1057     if (instance.find(registeredName) == 0)
1058     {
1059       anEngine = (*itm).second;
1060       if (studyId == anEngine->getStudyId())
1061       {
1062         return anEngine._retn();
1063       }
1064     }
1065     itm++;
1066   }
1067   return anEngine._retn();
1068 }
1069
1070 //=============================================================================
1071 //! Remove the component instance from container
1072 /*!
1073 *  CORBA method: Stops the component servant, and deletes all related objects
1074 *  \param component_i     Component to be removed
1075 */
1076 //=============================================================================
1077
1078 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
1079 {
1080   ASSERT(! CORBA::is_nil(component_i));
1081   string instanceName = component_i->instanceName() ;
1082   MESSAGE("unload component " << instanceName);
1083   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1084   _listInstances_map.erase(instanceName);
1085   _numInstanceMutex.unlock() ;
1086   component_i->destroy() ;
1087   _NS->Destroy_Name(instanceName.c_str());
1088 }
1089
1090 //=============================================================================
1091 //! Unload component libraries from the container
1092 /*!
1093 *  CORBA method: Discharges unused libraries from the container.
1094 */
1095 //=============================================================================
1096 void Engines_Container_i::finalize_removal()
1097 {
1098   MESSAGE("finalize unload : dlclose");
1099   _numInstanceMutex.lock(); // lock to be alone
1100   // (see decInstanceCnt, load_component_Library)
1101   map<string, void *>::iterator ith;
1102   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
1103   {
1104     void *handle = (*ith).second;
1105     string impl_name= (*ith).first;
1106     if (handle)
1107     {
1108       SCRUTE(handle);
1109       SCRUTE(impl_name);
1110       //        dlclose(handle);                // SALOME unstable after ...
1111       //        _library_map.erase(impl_name);
1112     }
1113   }
1114   _toRemove_map.clear();
1115   _numInstanceMutex.unlock();
1116 }
1117
1118 //=============================================================================
1119 //! Decrement component instance reference count
1120 /*!
1121 *
1122 */
1123 //=============================================================================
1124 void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1125 {
1126   if(_cntInstances_map.count(genericRegisterName)==0)
1127     return;
1128   string aGenRegisterName =genericRegisterName;
1129   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1130   ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1131   _numInstanceMutex.lock(); // lock to be alone
1132   // (see finalize_removal, load_component_Library)
1133   _cntInstances_map[aGenRegisterName] -= 1;
1134   SCRUTE(_cntInstances_map[aGenRegisterName]);
1135   if (_cntInstances_map[aGenRegisterName] == 0)
1136   {
1137     string impl_name =
1138       Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1139     SCRUTE(impl_name);
1140     void* handle = _library_map[impl_name];
1141     ASSERT(handle);
1142     _toRemove_map[impl_name] = handle;
1143   }
1144   _numInstanceMutex.unlock();
1145 }
1146
1147 //=============================================================================
1148 //! Find or create a new component instance
1149 /*!
1150 *  CORBA method: find or create an instance of the component (servant),
1151 *  load a new component class (dynamic library) if required,
1152 *
1153 *  ---- FOR COMPATIBILITY WITH 2.2 ----
1154 *
1155 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1156 *
1157 *  The servant registers itself to naming service and Registry.
1158 *  \param genericRegisterName  Name of the component to register
1159 *                              in Registry & Name Service
1160 *  \param componentName       Name of the constructed library of the component
1161 *  \return a loaded component
1162 */
1163 //=============================================================================
1164
1165 Engines::Component_ptr
1166 Engines_Container_i::load_impl( const char* genericRegisterName,
1167                                 const char* componentName )
1168 {
1169   char* reason;
1170   string impl_name = string(LIB) + genericRegisterName + ENGINESO;
1171   Engines::Component_var iobject = Engines::Component::_nil() ;
1172   if (load_component_Library(genericRegisterName,reason))
1173     iobject = find_or_create_instance(genericRegisterName, impl_name);
1174   CORBA::string_free(reason);
1175   return iobject._retn();
1176 }
1177
1178 //=============================================================================
1179 //! Finds an already existing component instance or create a new instance
1180 /*!
1181 *  C++ method: Finds an already existing servant instance of a component, or
1182 *              create an instance.
1183 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1184 *  \param genericRegisterName    Name of the component instance to register
1185 *                                in Registry & Name Service,
1186 *                                (without _inst_n suffix, like "COMPONENT")
1187 *  \param componentLibraryName   like "libCOMPONENTEngine.so"
1188 *  \return a loaded component
1189 *
1190 *  example with names:
1191 *    - aGenRegisterName = COMPONENT (= first argument)
1192 *    - impl_name = libCOMPONENTEngine.so (= second argument)
1193 *    - _containerName = /Containers/cli76ce/FactoryServer
1194 *    - factoryName = COMPONENTEngine_factory
1195 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1196 *    - instanceName = COMPONENT_inst_1
1197 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1198 */
1199 //=============================================================================
1200
1201 Engines::Component_ptr
1202 Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1203                                              std::string componentLibraryName)
1204 {
1205   string aGenRegisterName = genericRegisterName;
1206   string impl_name = componentLibraryName;
1207   if (_library_map.count(impl_name) == 0)
1208   {
1209     INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1210     return Engines::Component::_nil() ;
1211   }
1212   else
1213   {
1214     // --- find a registered instance in naming service, or create
1215
1216     void* handle = _library_map[impl_name];
1217     string component_registerBase =
1218       _containerName + "/" + aGenRegisterName;
1219     Engines::Component_var iobject = Engines::Component::_nil() ;
1220     std::string reason;
1221     try
1222     {
1223       CORBA::Object_var obj =
1224         _NS->ResolveFirst( component_registerBase.c_str());
1225       if ( CORBA::is_nil( obj ) )
1226       {
1227         iobject = createInstance(genericRegisterName,
1228                                  handle,
1229                                  0,
1230                                  reason); // force multiStudy instance here !
1231       }
1232       else
1233       {
1234         iobject = Engines::Component::_narrow( obj ) ;
1235         Engines_Component_i *servant =
1236           dynamic_cast<Engines_Component_i*>
1237           (_poa->reference_to_servant(iobject));
1238         ASSERT(servant)
1239           int studyId = servant->getStudyId();
1240         ASSERT (studyId >= 0);
1241         if (studyId == 0) // multiStudy instance, OK
1242         {
1243           // No ReBind !
1244           MESSAGE(component_registerBase.c_str()<<" already bound");
1245         }
1246         else // monoStudy instance: NOK
1247         {
1248           iobject = Engines::Component::_nil();
1249           INFOS("load_impl & find_component_instance methods "
1250             << "NOT SUITABLE for mono study components");
1251         }
1252       }
1253     }
1254     catch (...)
1255     {
1256       INFOS( "Container_i::load_impl catched" ) ;
1257     }
1258     return iobject._retn();
1259   }
1260 }
1261
1262 //=============================================================================
1263 //! Indicate if container is a python one
1264 /*! 
1265 *  Retrieves only with container naming convention if it is a python container
1266 */
1267 //=============================================================================
1268 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
1269 {
1270   bool ret=false;
1271   int len=strlen(ContainerName);
1272   if(len>=2)
1273     if(strcmp(ContainerName+len-2,"Py")==0)
1274       ret=true;
1275   return ret;
1276 }
1277
1278 //=============================================================================
1279 //! Kill the container
1280 /*!
1281 *  CORBA method: Kill the container process with exit(0).
1282 *  To remove :  never returns !
1283 */
1284 //=============================================================================
1285 bool Engines_Container_i::Kill_impl()
1286 {
1287   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
1288     << _containerName.c_str() << " machineName "
1289     << Kernel_Utils::GetHostname().c_str());
1290   INFOS("===============================================================");
1291   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
1292   INFOS("===============================================================");
1293   //_exit( 0 ) ;
1294   ASSERT(0);
1295   return false;
1296 }
1297
1298 //=============================================================================
1299 /*! 
1300 *  
1301 */
1302 //=============================================================================
1303 void ActSigIntHandler()
1304 {
1305 #ifndef WIN32
1306   struct sigaction SigIntAct ;
1307   SigIntAct.sa_sigaction = &SigIntHandler ;
1308   sigemptyset(&SigIntAct.sa_mask);
1309   SigIntAct.sa_flags = SA_SIGINFO ;
1310 #endif
1311
1312   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1313   // (SIGINT | SIGUSR1) :
1314   // it must be only one signal ===> one call for SIGINT 
1315   // and an other one for SIGUSR1
1316
1317 #ifndef WIN32
1318   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
1319   {
1320     perror("SALOME_Container main ") ;
1321     exit(0) ;
1322   }
1323   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1324   {
1325     perror("SALOME_Container main ") ;
1326     exit(0) ;
1327   }
1328   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1329   {
1330     perror("SALOME_Container main ") ;
1331     exit(0) ;
1332   }
1333
1334   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1335   //             use of streams (and so on) should never be used because :
1336   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1337   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1338   //             may have a "Dead-Lock" ===HangUp
1339   //==INFOS is commented
1340   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1341
1342 #else  
1343   signal( SIGINT, SigIntHandler );
1344   signal( SIGUSR1, SigIntHandler );
1345 #endif
1346
1347 }
1348
1349 void SetCpuUsed() ;
1350 void CallCancelThread() ;
1351
1352 #ifndef WIN32
1353 void SigIntHandler(int what ,
1354                    siginfo_t * siginfo ,
1355                    void * toto ) 
1356 {
1357   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1358   //             use of streams (and so on) should never be used because :
1359   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1360   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1361   //             may have a "Dead-Lock" ===HangUp
1362   //==MESSAGE is commented
1363   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
1364   //          << "              si_signo " << siginfo->si_signo << endl
1365   //          << "              si_code  " << siginfo->si_code << endl
1366   //          << "              si_pid   " << siginfo->si_pid) ;
1367
1368   if ( _Sleeping )
1369   {
1370     _Sleeping = false ;
1371     //     MESSAGE("SigIntHandler END sleeping.") ;
1372     return ;
1373   }
1374   else
1375   {
1376     ActSigIntHandler() ;
1377     if ( siginfo->si_signo == SIGUSR1 )
1378     {
1379       SetCpuUsed() ;
1380     }
1381     else if ( siginfo->si_signo == SIGUSR2 )
1382     {
1383       CallCancelThread() ;
1384     }
1385     else 
1386     {
1387       _Sleeping = true ;
1388       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1389       int count = 0 ;
1390       while( _Sleeping )
1391       {
1392         sleep( 1 ) ;
1393         count += 1 ;
1394       }
1395       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1396     }
1397     return ;
1398   }
1399 }
1400 #else // Case WIN32
1401 void SigIntHandler( int what )
1402 {
1403 #ifndef WIN32
1404   MESSAGE( pthread_self() << "SigIntHandler what     " << what << endl );
1405 #else
1406   MESSAGE( "SigIntHandler what     " << what << endl );
1407 #endif
1408   if ( _Sleeping )
1409   {
1410     _Sleeping = false ;
1411     MESSAGE("SigIntHandler END sleeping.") ;
1412     return ;
1413   }
1414   else
1415   {
1416     ActSigIntHandler() ;
1417     if ( what == SIGUSR1 )
1418     {
1419       SetCpuUsed() ;
1420     }
1421     else
1422     {
1423       _Sleeping = true ;
1424       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1425       int count = 0 ;
1426       while( _Sleeping ) 
1427       {
1428         Sleep( 1000 ) ;
1429         count += 1 ;
1430       }
1431       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1432     }
1433     return ;
1434   }
1435 }
1436 #endif
1437
1438 //=============================================================================
1439 //! Get or create a file reference object associated to a local file (to transfer it)
1440 /*!
1441 *  CORBA method: get or create a fileRef object associated to a local file
1442 *  (a file on the computer on which runs the container server), which stores
1443 *  a list of (machine, localFileName) corresponding to copies already done.
1444 *
1445 *  \param  origFileName absolute path for a local file to copy on other
1446 *          computers
1447 *  \return a fileRef object associated to the file.
1448 */
1449 //=============================================================================
1450 Engines::fileRef_ptr
1451 Engines_Container_i::createFileRef(const char* origFileName)
1452 {
1453   string origName(origFileName);
1454   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
1455
1456   if (origName[0] != '/')
1457   {
1458     INFOS("path of file to copy must be an absolute path begining with '/'");
1459     return Engines::fileRef::_nil();
1460   }
1461
1462   if (CORBA::is_nil(_fileRef_map[origName]))
1463   {
1464     CORBA::Object_var obj=_poa->id_to_reference(*_id);
1465     Engines::Container_var pCont = Engines::Container::_narrow(obj);
1466     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
1467     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
1468     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1469     _fileRef_map[origName] = theFileRef;
1470     _numInstanceMutex.unlock() ;
1471   }
1472
1473   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
1474   ASSERT(! CORBA::is_nil(theFileRef));
1475   return theFileRef._retn();
1476 }
1477
1478 //=============================================================================
1479 //! Get a fileTransfer reference
1480 /*!
1481 *  CORBA method:
1482 *  \return a reference to the fileTransfer object
1483 */
1484 //=============================================================================
1485 Engines::fileTransfer_ptr
1486 Engines_Container_i::getFileTransfer()
1487 {
1488   Engines::fileTransfer_var aFileTransfer
1489     = Engines::fileTransfer::_duplicate(_fileTransfer);
1490   return aFileTransfer._retn();
1491 }
1492
1493 //=============================================================================
1494 //! Create a Salome file
1495 //=============================================================================
1496 Engines::Salome_file_ptr
1497 Engines_Container_i::createSalome_file(const char* origFileName)
1498 {
1499   string origName(origFileName);
1500   if (CORBA::is_nil(_Salome_file_map[origName]))
1501   {
1502     Salome_file_i* aSalome_file = new Salome_file_i();
1503     aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1504     try
1505     {
1506       aSalome_file->setLocalFile(origFileName);
1507       aSalome_file->recvFiles();
1508     }
1509     catch (const SALOME::SALOME_Exception& e)
1510     {
1511       return Engines::Salome_file::_nil();
1512     }
1513
1514     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1515     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1516     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1517     _Salome_file_map[origName] = theSalome_file;
1518     _numInstanceMutex.unlock() ;
1519   }
1520
1521   Engines::Salome_file_ptr theSalome_file =
1522     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1523   ASSERT(!CORBA::is_nil(theSalome_file));
1524   return theSalome_file;
1525 }
1526
1527 //=============================================================================
1528 /*! \brief copy a file from a remote host (container) to the local host
1529  * \param container the remote container
1530  * \param remoteFile the file to copy locally from the remote host into localFile
1531  * \param localFile the local file
1532  */
1533 //=============================================================================
1534 void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1535 {
1536   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1537
1538   FILE* fp;
1539   if ((fp = fopen(localFile,"wb")) == NULL)
1540     {
1541       INFOS("file " << localFile << " cannot be open for writing");
1542       return;
1543     }
1544
1545   CORBA::Long fileId = fileTransfer->open(remoteFile);
1546   if (fileId > 0)
1547     {
1548       Engines::fileBlock* aBlock;
1549       int toFollow = 1;
1550       int ctr=0;
1551       while (toFollow)
1552         {
1553           ctr++;
1554           SCRUTE(ctr);
1555           aBlock = fileTransfer->getBlock(fileId);
1556           toFollow = aBlock->length();
1557           SCRUTE(toFollow);
1558           CORBA::Octet *buf = aBlock->get_buffer();
1559           fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1560           delete aBlock;
1561         }
1562       fclose(fp);
1563       MESSAGE("end of transfer");
1564       fileTransfer->close(fileId);
1565     }
1566   else
1567     {
1568       INFOS("open reference file for copy impossible");
1569     }
1570 }
1571
1572 //=============================================================================
1573 /*! \brief create a PyNode object to execute remote python code
1574  * \param nodeName the name of the node
1575  * \param code the python code to load
1576  * \return the PyNode
1577  */
1578 //=============================================================================
1579 Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
1580 {
1581     Engines::PyNode_var node= Engines::PyNode::_nil();
1582
1583     PyGILState_STATE gstate = PyGILState_Ensure();
1584     PyObject *res = PyObject_CallMethod(_pyCont,
1585       (char*)"create_pynode",
1586       (char*)"ss",
1587       nodeName,
1588       code);
1589     if(res==NULL)
1590       {
1591         //internal error
1592         PyErr_Print();
1593         PyGILState_Release(gstate);
1594         SALOME::ExceptionStruct es;
1595         es.type = SALOME::INTERNAL_ERROR;
1596         es.text = "can not create a python node";
1597         throw SALOME::SALOME_Exception(es);
1598       }
1599     long ierr=PyInt_AsLong(PyTuple_GetItem(res,0));
1600     PyObject* result=PyTuple_GetItem(res,1);
1601     std::string astr=PyString_AsString(result);
1602     Py_DECREF(res);
1603     PyGILState_Release(gstate);
1604
1605     if(ierr==0)
1606       {
1607         CORBA::Object_var obj = _orb->string_to_object(astr.c_str());
1608         node = Engines::PyNode::_narrow(obj);
1609         return node._retn();
1610       }
1611     else
1612       {
1613         SALOME::ExceptionStruct es;
1614         es.type = SALOME::INTERNAL_ERROR;
1615         es.text = astr.c_str();
1616         throw SALOME::SALOME_Exception(es);
1617       }
1618
1619 }
1620
1621 //=============================================================================
1622 /* int checkifexecutable(const char *filename)
1623 *
1624 * Return non-zero if the name is an executable file, and
1625 * zero if it is not executable, or if it does not exist.
1626 */
1627 //=============================================================================
1628 int checkifexecutable(const string& filename)
1629 {
1630   int result;
1631   struct stat statinfo;
1632
1633   result = stat(filename.c_str(), &statinfo);
1634   if (result < 0) return 0;
1635   if (!S_ISREG(statinfo.st_mode)) return 0;
1636
1637 #ifdef WIN32
1638   return 1;
1639 #else
1640   if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
1641   if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
1642   return statinfo.st_mode & S_IXOTH;
1643 #endif
1644 }
1645
1646
1647 //=============================================================================
1648 /*! \brief Find a file by searching in a path
1649  *  \param filename file name to search
1650  *  \param path path to search in
1651  *  \param pth the complete file path if found
1652  *  \return 1 if found 0 if not 
1653 */
1654 //=============================================================================
1655 int findpathof(const std::string& path, std::string& pth, const std::string& filename)
1656 {
1657   if ( path.size() == 0 ) return 0;
1658
1659   std::string::size_type offset = 0;
1660   std::string::size_type pos = 0;
1661   int found = 0;
1662   struct stat statinfo;
1663
1664   while(!found)
1665   {
1666     pos = path.find( SEP, offset );
1667     pth = path.substr( offset, pos - offset );
1668     if ( pth.size() > 0 )
1669     {
1670       if( pth[pth.size()-1] != SLASH ) pth += SLASH;
1671       pth += filename;
1672       int result=stat(pth.c_str(), &statinfo);
1673       if(result == 0) found=1;
1674     }
1675     if (pos == string::npos) break;
1676     offset = pos+1;
1677   }
1678   return found;
1679 }
1680