Salome HOME
CCAR: add the PyNode object that can be created in a container
[modules/kernel.git] / src / Container / Container_i.cxx
index 954c8fcf7fce4dce9082ac1977a7fb92ef527e58..f7124ac82ba1074dd5e62579b0db86329bf985ff 100644 (file)
@@ -64,10 +64,6 @@ bool _Sleeping = false ;
 int _ArgC ;
 char ** _ArgV ;
 
-
-// Containers with name FactoryServer are started via rsh in LifeCycleCORBA
-// Other Containers are started via start_impl of FactoryServer
-
 extern "C" {void ActSigIntHandler() ; }
 #ifndef WIN32
 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
@@ -87,6 +83,17 @@ map<std::string, void *> Engines_Container_i::_library_map;
 map<std::string, void *> Engines_Container_i::_toRemove_map;
 omni_mutex Engines_Container_i::_numInstanceMutex ;
 
+static PyObject* _pyCont;
+
+int checkifexecutable(const std::string&);
+int findpathof(std::string&, const std::string&);
+
+/*! \class Engines_Container_i
+ *  \brief C++ implementation of Engines::Container interface
+ *
+ */
+
+
 //=============================================================================
 /*! 
 *  Default constructor, not for use
@@ -94,7 +101,7 @@ omni_mutex Engines_Container_i::_numInstanceMutex ;
 //=============================================================================
 
 Engines_Container_i::Engines_Container_i () :
-_numInstance(0)
+_numInstance(0),_id(0),_NS(0)
 {
 }
 
@@ -111,7 +118,7 @@ Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb,
                                           bool activAndRegist,
                                           bool isServantAloneInProcess
                                           ) :
-_numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
+  _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess),_id(0),_NS(0)
 {
   _pid = (long)getpid();
 
@@ -189,14 +196,7 @@ _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
 
     if (!_isSupervContainer)
     {
-#ifdef WIN32
-
-      PyEval_AcquireLock();
-      PyThreadState *myTstate = PyThreadState_New(KERNEL_PYTHON::_interp);
-      PyThreadState *myoldTstate = PyThreadState_Swap(myTstate);
-#else
-      Py_ACQUIRE_NEW_THREAD;
-#endif
+      PyGILState_STATE gstate = PyGILState_Ensure();
 
 #ifdef WIN32
       // mpv: this is temporary solution: there is a unregular crash if not
@@ -208,7 +208,11 @@ _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
 #endif
       PyRun_SimpleString("import SALOME_Container\n");
       PyRun_SimpleString((char*)myCommand.c_str());
-      Py_RELEASE_NEW_THREAD;
+      PyObject *mainmod = PyImport_AddModule("__main__");
+      PyObject *globals = PyModule_GetDict(mainmod);
+      _pyCont = PyDict_GetItemString(globals, "pyCont");
+
+      PyGILState_Release(gstate);
     }
 
     fileTransfer_i* aFileTransfer = new fileTransfer_i();
@@ -227,12 +231,14 @@ _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
 Engines_Container_i::~Engines_Container_i()
 {
   MESSAGE("Container_i::~Container_i()");
-  delete _id;
+  if(_id)
+    delete _id;
   if(_NS)
     delete _NS;
 }
 
 //=============================================================================
+//! Get container name
 /*! 
 *  CORBA attribute: Container name (see constructor)
 */
@@ -244,6 +250,7 @@ char* Engines_Container_i::name()
 }
 
 //=============================================================================
+//! Get container working directory
 /*! 
 *  CORBA attribute: Container working directory 
 */
@@ -257,6 +264,7 @@ char* Engines_Container_i::workingdir()
 }
 
 //=============================================================================
+//! Get container log file name
 /*! 
 *  CORBA attribute: Container log file name
 */
@@ -267,12 +275,14 @@ char* Engines_Container_i::logfilename()
   return CORBA::string_dup(_logfilename.c_str()) ;
 }
 
+//! Set container log file name
 void Engines_Container_i::logfilename(const char* name)
 {
   _logfilename=name;
 }
 
 //=============================================================================
+//! Get container host name
 /*! 
 *  CORBA method: Get the hostName of the Container (without domain extensions)
 */
@@ -286,6 +296,7 @@ char* Engines_Container_i::getHostName()
 }
 
 //=============================================================================
+//! Get container PID
 /*! 
 *  CORBA method: Get the PID (process identification) of the Container
 */
@@ -297,6 +308,7 @@ CORBA::Long Engines_Container_i::getPID()
 }
 
 //=============================================================================
+//! Ping the servant to check it is still alive
 /*! 
 *  CORBA method: check if servant is still alive
 */
@@ -308,6 +320,7 @@ void Engines_Container_i::ping()
 }
 
 //=============================================================================
+//! Shutdown the container
 /*! 
 *  CORBA method, oneway: Server shutdown. 
 *  - Container name removed from naming service,
@@ -339,11 +352,10 @@ void Engines_Container_i::Shutdown()
           // ignore this entry and continue
         }
     }
+  _listInstances_map.clear();
 
   _NS->Destroy_FullDirectory(_containerName.c_str());
   _NS->Destroy_Name(_containerName.c_str());
-  //_remove_ref();
-  //_poa->deactivate_object(*_id);
   if(_isServantAloneInProcess)
   {
     MESSAGE("Effective Shutdown of container Begins...");
@@ -393,8 +405,8 @@ int findpathof(string& pth, const string& exe)
 {
   string path( getenv("PATH") );
   if ( path.size() == 0 )
-         return 0;
-       
+         return 0;
+       
   char path_spr =
 #ifdef WIN32
                   ';';
@@ -473,6 +485,7 @@ int findpathof(string& pth, const string& exe)
 
 
 //=============================================================================
+//! load a new component class
 /*! 
 *  CORBA method: load a new component class (Python or C++ implementation)
 *  \param componentName like COMPONENT
@@ -507,9 +520,11 @@ Engines_Container_i::load_component_Library(const char* componentName)
     return true;
   }
 
+  std::string retso="";
 #ifndef WIN32
   void* handle;
   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
+  if ( !handle )retso=dlerror();
 #else
   HINSTANCE handle;
   handle = LoadLibrary( impl_name.c_str() );
@@ -526,6 +541,7 @@ Engines_Container_i::load_component_Library(const char* componentName)
   // --- try import Python component
 
   INFOS("try import Python component "<<componentName);
+  std::string retpy;
   if (_isSupervContainer)
   {
     INFOS("Supervision Container does not support Python Component Engines");
@@ -537,22 +553,20 @@ Engines_Container_i::load_component_Library(const char* componentName)
   }
   else
   {
-    Py_ACQUIRE_NEW_THREAD;
-    PyObject *mainmod = PyImport_AddModule("__main__");
-    PyObject *globals = PyModule_GetDict(mainmod);
-    PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
-    PyObject *result = PyObject_CallMethod(pyCont,
+    PyGILState_STATE gstate = PyGILState_Ensure(); 
+    PyObject *result = PyObject_CallMethod(_pyCont,
       (char*)"import_component",
       (char*)"s",componentName);
-    int ret= PyInt_AsLong(result);
+
+    retpy=PyString_AsString(result);
     Py_XDECREF(result);
-    SCRUTE(ret);
-    Py_RELEASE_NEW_THREAD;
+    SCRUTE(retpy);
+    PyGILState_Release(gstate);
 
-    if (ret) // import possible: Python component
+    if (retpy=="") // import possible: Python component
     {
       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
-      _library_map[aCompName] = (void *)pyCont; // any non O value OK
+      _library_map[aCompName] = (void *)_pyCont; // any non O value OK
       _numInstanceMutex.unlock() ;
       MESSAGE("import Python: "<<aCompName<<" OK");
       return true;
@@ -566,12 +580,15 @@ Engines_Container_i::load_component_Library(const char* componentName)
 
   INFOS( "Impossible to load component: " << componentName );
   INFOS( "Can't load shared library: " << impl_name );
+  std::cerr << retso << std::endl;
   INFOS( "Can't import Python module: " << componentName );
+  std::cerr << retpy << std::endl;
   INFOS( "Can't execute program: " << executable );
   return false;
 }
 
 //=============================================================================
+//! Create a new component instance
 /*! 
 *  CORBA method: Creates a new servant instance of a component.
 *  The servant registers itself to naming service and Registry.
@@ -614,11 +631,8 @@ Engines_Container_i::create_component_instance(const char*genericRegisterName,
     string component_registerName =
       _containerName + "/" + instanceName;
 
-    Py_ACQUIRE_NEW_THREAD;
-    PyObject *mainmod = PyImport_AddModule("__main__");
-    PyObject *globals = PyModule_GetDict(mainmod);
-    PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
-    PyObject *result = PyObject_CallMethod(pyCont,
+    PyGILState_STATE gstate = PyGILState_Ensure(); 
+    PyObject *result = PyObject_CallMethod(_pyCont,
       (char*)"create_component_instance",
       (char*)"ssl",
       aCompName.c_str(),
@@ -627,7 +641,7 @@ Engines_Container_i::create_component_instance(const char*genericRegisterName,
     string iors = PyString_AsString(result);
     Py_DECREF(result);
     SCRUTE(iors);
-    Py_RELEASE_NEW_THREAD;
+    PyGILState_Release(gstate);
 
     if( iors!="" )
     {
@@ -749,6 +763,7 @@ Engines_Container_i::create_component_instance(const char*genericRegisterName,
 }
 
 //=============================================================================
+//! Find an existing (in the container) component instance
 /*! 
 *  CORBA method: Finds a servant instance of a component
 *  \param registeredName  Name of the component in Registry or Name Service,
@@ -783,11 +798,15 @@ Engines_Container_i::find_component_instance( const char* registeredName,
 }
 
 //=============================================================================
+//! Find or create a new component instance
 /*! 
 *  CORBA method: find or create an instance of the component (servant),
 *  load a new component class (dynamic library) if required,
+*
 *  ---- FOR COMPATIBILITY WITH 2.2 ---- 
+*
 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
+*
 *  The servant registers itself to naming service and Registry.
 *  \param genericRegisterName  Name of the component to register
 *                              in Registry & Name Service
@@ -809,6 +828,7 @@ Engines_Container_i::load_impl( const char* genericRegisterName,
 
 
 //=============================================================================
+//! Remove the component instance from container
 /*! 
 *  CORBA method: Stops the component servant, and deletes all related objects
 *  \param component_i     Component to be removed
@@ -828,6 +848,7 @@ void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
 }
 
 //=============================================================================
+//! Unload component libraries from the container
 /*! 
 *  CORBA method: Discharges unused libraries from the container.
 */
@@ -856,6 +877,7 @@ void Engines_Container_i::finalize_removal()
 }
 
 //=============================================================================
+//! Kill the container
 /*! 
 *  CORBA method: Kill the container process with exit(0).
 *  To remove :  never returns !
@@ -876,6 +898,7 @@ bool Engines_Container_i::Kill_impl()
 }
 
 //=============================================================================
+//! Get or create a file reference object associated to a local file (to transfer it)
 /*! 
 *  CORBA method: get or create a fileRef object associated to a local file
 *  (a file on the computer on which runs the container server), which stores
@@ -916,6 +939,7 @@ Engines_Container_i::createFileRef(const char* origFileName)
 }
 
 //=============================================================================
+//! Get a fileTransfer reference
 /*! 
 *  CORBA method:
 *  \return a reference to the fileTransfer object
@@ -931,6 +955,7 @@ Engines_Container_i::getFileTransfer()
 }
 
 
+//! Create a Salome file
 Engines::Salome_file_ptr 
 Engines_Container_i::createSalome_file(const char* origFileName) 
 {
@@ -962,6 +987,7 @@ Engines_Container_i::createSalome_file(const char* origFileName)
   return theSalome_file;
 }
 //=============================================================================
+//! Finds an already existing component instance or create a new instance
 /*! 
 *  C++ method: Finds an already existing servant instance of a component, or
 *              create an instance.
@@ -973,20 +999,19 @@ Engines_Container_i::createSalome_file(const char* origFileName)
 *  \return a loaded component
 * 
 *  example with names:
-*  aGenRegisterName = COMPONENT (= first argument)
-*  impl_name = libCOMPONENTEngine.so (= second argument)
-*  _containerName = /Containers/cli76ce/FactoryServer
-*  factoryName = COMPONENTEngine_factory
-*  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
-*
-*  instanceName = COMPONENT_inst_1
-*  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
+*    - aGenRegisterName = COMPONENT (= first argument)
+*    - impl_name = libCOMPONENTEngine.so (= second argument)
+*    - _containerName = /Containers/cli76ce/FactoryServer
+*    - factoryName = COMPONENTEngine_factory
+*    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
+*    - instanceName = COMPONENT_inst_1
+*    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
 */
 //=============================================================================
 
 Engines::Component_ptr
-Engines_Container_i::find_or_create_instance(string genericRegisterName,
-                                             string componentLibraryName)
+Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
+                                             std::string componentLibraryName)
 {
   string aGenRegisterName = genericRegisterName;
   string impl_name = componentLibraryName;
@@ -1044,6 +1069,7 @@ Engines_Container_i::find_or_create_instance(string genericRegisterName,
 }
 
 //=============================================================================
+//! Create a new component instance 
 /*! 
 *  C++ method: create a servant instance of a component.
 *  \param genericRegisterName    Name of the component instance to register
@@ -1055,17 +1081,17 @@ Engines_Container_i::find_or_create_instance(string genericRegisterName,
 *  \return a loaded component
 * 
 *  example with names:
-*  aGenRegisterName = COMPONENT (= first argument)
-*  _containerName = /Containers/cli76ce/FactoryServer
-*  factoryName = COMPONENTEngine_factory
-*  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
-*  instanceName = COMPONENT_inst_1
-*  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
+*    - aGenRegisterName = COMPONENT (= first argument)
+*    - _containerName = /Containers/cli76ce/FactoryServer
+*    - factoryName = COMPONENTEngine_factory
+*    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
+*    - instanceName = COMPONENT_inst_1
+*    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
 */
 //=============================================================================
 
 Engines::Component_ptr
-Engines_Container_i::createInstance(string genericRegisterName,
+Engines_Container_i::createInstance(std::string genericRegisterName,
                                     void *handle,
                                     int studyId)
 {
@@ -1130,22 +1156,16 @@ Engines_Container_i::createInstance(string genericRegisterName,
     Engines_Component_i *servant =
       dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
     ASSERT(servant);
-    //SCRUTE(servant->pd_refCount);
-    servant->_remove_ref(); // compensate previous id_to_reference 
-    //SCRUTE(servant->pd_refCount);
+    //SCRUTE(servant->_refcount_value());
     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
     _listInstances_map[instanceName] = iobject;
     _cntInstances_map[aGenRegisterName] += 1;
     _numInstanceMutex.unlock() ;
     SCRUTE(aGenRegisterName);
     SCRUTE(_cntInstances_map[aGenRegisterName]);
-    //SCRUTE(servant->pd_refCount);
-#if defined(_DEBUG_) || defined(_DEBUG)
-    bool ret_studyId = servant->setStudyId(studyId);
-    ASSERT(ret_studyId);
-#else
     servant->setStudyId(studyId);
-#endif
+    servant->_remove_ref(); // do not need servant any more (remove ref from reference_to_servant)
+    //SCRUTE(servant->_refcount_value());
 
     // --- register the engine under the name
     //     containerName(.dir)/instanceName(.object)
@@ -1161,12 +1181,13 @@ Engines_Container_i::createInstance(string genericRegisterName,
 }
 
 //=============================================================================
+//! Decrement component instance reference count
 /*! 
 *
 */
 //=============================================================================
 
-void Engines_Container_i::decInstanceCnt(string genericRegisterName)
+void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
 {
   if(_cntInstances_map.count(genericRegisterName)==0)
     return;
@@ -1190,6 +1211,7 @@ void Engines_Container_i::decInstanceCnt(string genericRegisterName)
 }
 
 //=============================================================================
+//! Indicate if container is a python one
 /*! 
 *  Retrieves only with container naming convention if it is a python container
 */
@@ -1216,6 +1238,7 @@ void ActSigIntHandler()
 #ifndef WIN32
   struct sigaction SigIntAct ;
   SigIntAct.sa_sigaction = &SigIntHandler ;
+  sigemptyset(&SigIntAct.sa_mask);
   SigIntAct.sa_flags = SA_SIGINFO ;
 #endif
 
@@ -1344,3 +1367,93 @@ void SigIntHandler( int what )
   }
 }
 #endif
+
+/*! \brief copy a file from a remote host (container) to the local host
+ * \param container the remote container
+ * \param remoteFile the file to copy locally from the remote host into localFile
+ * \param localFile the local file
+ */
+void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
+{
+  Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
+
+  FILE* fp;
+  if ((fp = fopen(localFile,"wb")) == NULL)
+    {
+      INFOS("file " << localFile << " cannot be open for writing");
+      return;
+    }
+
+  CORBA::Long fileId = fileTransfer->open(remoteFile);
+  if (fileId > 0)
+    {
+      Engines::fileBlock* aBlock;
+      int toFollow = 1;
+      int ctr=0;
+      while (toFollow)
+        {
+          ctr++;
+          SCRUTE(ctr);
+          aBlock = fileTransfer->getBlock(fileId);
+          toFollow = aBlock->length();
+          SCRUTE(toFollow);
+          CORBA::Octet *buf = aBlock->get_buffer();
+          fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
+          delete aBlock;
+        }
+      fclose(fp);
+      MESSAGE("end of transfer");
+      fileTransfer->close(fileId);
+    }
+  else
+    {
+      INFOS("open reference file for copy impossible");
+    }
+}
+
+/*! \brief create a PyNode object to execute remote python code
+ * \param nodeName the name of the node
+ * \param code the python code to load
+ * \return the PyNode
+ */
+Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
+{
+    Engines::PyNode_var node= Engines::PyNode::_nil();
+
+    PyGILState_STATE gstate = PyGILState_Ensure();
+    PyObject *res = PyObject_CallMethod(_pyCont,
+      (char*)"create_pynode",
+      (char*)"ss",
+      nodeName,
+      code);
+    if(res==NULL)
+      {
+        //internal error
+        PyErr_Print();
+        PyGILState_Release(gstate);
+        SALOME::ExceptionStruct es;
+        es.type = SALOME::INTERNAL_ERROR;
+        es.text = "can not create a python node";
+        throw SALOME::SALOME_Exception(es);
+      }
+    long ierr=PyInt_AsLong(PyTuple_GetItem(res,0));
+    PyObject* result=PyTuple_GetItem(res,1);
+    std::string astr=PyString_AsString(result);
+    Py_DECREF(res);
+    PyGILState_Release(gstate);
+
+    if(ierr==0)
+      {
+        CORBA::Object_var obj = _orb->string_to_object(astr.c_str());
+        node = Engines::PyNode::_narrow(obj);
+        return node._retn();
+      }
+    else
+      {
+        SALOME::ExceptionStruct es;
+        es.type = SALOME::INTERNAL_ERROR;
+        es.text = astr.c_str();
+        throw SALOME::SALOME_Exception(es);
+      }
+
+}