Salome HOME
[EDF30062] : Forward of current directory mecanism
[modules/kernel.git] / src / KERNEL_PY / __init__.py
old mode 100755 (executable)
new mode 100644 (file)
index 1610404..6d7d732
@@ -1,5 +1,5 @@
 #  -*- coding: iso-8859-1 -*-
-# Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
 #
 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -26,7 +26,7 @@
 #  Module : SALOME
 #
 """ 
-Module salome gives access to Salome ressources.
+Module salome gives access to Salome resources.
 
 variables:
 
@@ -45,9 +45,7 @@ variables:
 
   - salome.sg              : salome object to communicate with the graphical user interface (if any)
       - methods:
-         - updateObjBrowser(bool):
-         - getActiveStudyId():
-         - getActiveStudyName():
+         - updateObjBrowser():
 
          - SelectedCount():      returns number of selected objects
          - getSelected(i):       returns entry of selected object number i
@@ -65,20 +63,18 @@ variables:
          - IDToObject(Entry):    returns CORBA reference from entry
 
   - salome.myStudyName     : active Study Name
-  - salome.myStudyId       : active Study Id
   - salome.myStudy         : the active Study itself (CORBA ior)
       - methods : defined in SALOMEDS.idl
 
 """
 ## @package salome
-# Module salome gives access to Salome ressources.
+# Module salome gives access to Salome resources.
 #
 #  \param salome.orb             : CORBA orb object
 #  \param salome.naming_service  : instance of naming Service class (SALOME_NamingServicePy::SALOME_NamingServicePy_i)
 #  \param salome.lcc             : instance of lifeCycleCORBA class (SALOME_LifeCycleCORBA)
 #  \param salome.sg              : Salome object to communicate with the graphical user interface, if running (see interface in salome_iapp::SalomeOutsideGUI)
 #  \param salome.myStudyName     : active Study Name
-#  \param salome.myStudyId       : active Study Id
 #  \param salome.myStudy         : the active Study (interface SALOMEDS::Study)
 
 #
@@ -140,7 +136,7 @@ if not flags:
         # dl module can be unavailable
         import dl
         flags = dl.RTLD_NOW | dl.RTLD_GLOBAL
-    except:
+    except Exception:
         pass
     pass
 if not flags:
@@ -148,7 +144,7 @@ if not flags:
         # DLFCN module can be unavailable
         import DLFCN
         flags = DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL
-    except:
+    except Exception:
         pass
     pass
 if not flags:
@@ -156,7 +152,7 @@ if not flags:
         # ctypes module can be unavailable
         import ctypes
         flags = ctypes.RTLD_GLOBAL
-    except:
+    except Exception:
         pass
     pass
 
@@ -165,63 +161,193 @@ if not flags:
 #    sys.setdlopenflags(flags)
 #    pass
 
-orb, lcc, naming_service, cm,sg=None,None,None,None,None
-myStudyManager, myStudyId, myStudy, myStudyName=None,None,None,None
+orb, lcc, naming_service, cm, sg, esm, dsm, logm, modulcat, rm = None,None,None,None,None,None,None,None,None,None
+myStudy, myStudyName = None,None
 
-def setCurrentStudy(theStudy):
-    """
-    Change current study : an existing one given by a study object.
+salome_initial=True
+
+def standalone():
+    pass
 
-    :param theStudy: the study CORBA object to set as current study
+def withServers():
+    import KernelBasis
+    KernelBasis.setSSLMode(False)
+
+def salome_init(path=None, embedded=False, iorfakensfile=None, forced=False):
+    """
+    Initialize SALOME client process (that can also be server).
+    3 modes of initialization exists:
+    - SSL mode (see salome_init_without_session)
+    - SSL mode attached in the context of python execution inside SALOME_Container_No_NS_Serv server (typically YACS)
+    - Classical mode (see salome_init_with_session)
+    :param iorfakensfile: filename inside which IOR of fake NS will be written
+    :param forced: tell if the multi-initialization protection mecanism of salome_init must be skiped of not
+                   (typically in the context where a path to a study is given whereas a previous initialisation without it was done)
     """
-    global myStudyId, myStudy, myStudyName
-    myStudyId, myStudy, myStudyName =salome_study.setCurrentStudy(theStudy)
+    if not forced:
+        if lcc is not None:# multi-initialization protection mecanism is based on lcc global var
+            return
+    PATH_TO_STUDY_FILE_TO_INITIATE = "PATH_TO_STUDY_FILE_TO_INITIATE"
+    import KernelBasis
+    if KernelBasis.getSSLMode():
+        if KernelBasis.getIOROfEmbeddedNS() == "":
+            import os
+            # make runSalome.py -t study.hdf toto.py
+            if path is None and PATH_TO_STUDY_FILE_TO_INITIATE in os.environ:
+                path = os.environ[PATH_TO_STUDY_FILE_TO_INITIATE]
+            salome_init_without_session(path, embedded, iorfakensfile)
+        else:
+            salome_init_without_session_attached(path, embedded)
+    else:
+        salome_init_with_session(path, embedded)
+
+def salome_init_without_session_common(path=None, embedded=False):
+    from ORBConfigFile import writeORBConfigFileSSL
+    OMNIORB_USER_PATH = "OMNIORB_USER_PATH"
+    def RemoveOmniorbConfigFile():
+        import os
+        if "OMNIORB_CONFIG" in os.environ:
+            fileToRemove = os.environ["OMNIORB_CONFIG"]
+            if os.path.exists(fileToRemove):
+                os.unlink(fileToRemove)
 
-def setCurrentStudyId(theStudyId=0):
+    if OMNIORB_USER_PATH in os.environ:
+        import atexit
+        writeORBConfigFileSSL(os.environ[OMNIORB_USER_PATH],kwargs={"with_pid":True})
+        atexit.register(RemoveOmniorbConfigFile)
+
+    global lcc,naming_service,myStudy,myStudyName,orb,modulcat,sg
+    import KernelBasis
+    KernelBasis.setSSLMode(True)
+    import KernelDS
+    myStudy = KernelDS.myStudy()
+    import CORBA
+    orb=CORBA.ORB_init([''])
+    import KernelModuleCatalog
+    import SALOME_ModuleCatalog
+    from salome_kernel import list_of_catalogs_regarding_environement
+    modulcat = KernelModuleCatalog.myModuleCatalog( list_of_catalogs_regarding_environement() )
+    #
+    poa = orb.resolve_initial_references("RootPOA")
+    poaManager = poa._get_the_POAManager()
+    poaManager.activate()
+    #
+    sg = salome_iapp_init(embedded)
+    salome_study_init_without_session(path)
+    #
+    from NamingService import NamingService
+    naming_service = NamingService()
+    myStudyName = myStudy.Name
+
+def salome_init_without_session(path=None, embedded=False, iorfakensfile=None):
+    """
+    Force creation of all servants needed by SALOME session in the current process.
+    A Fake NamingService is created storing reference of all servants in the current process.
     """
-    Change current study : an existing or new one given by Id.
+    salome_init_without_session_common(path,embedded)
+    global lcc,cm,dsm,esm,rm,logm
+    import KernelLauncher
+    cm = KernelLauncher.myContainerManager()
+    type(cm).SetOverrideEnvForContainersSimple = ContainerManagerSetOverrideEnvForContainersSimple
+    rm = KernelLauncher.myResourcesManager()
+    from LifeCycleCORBA import LifeCycleCORBASSL
+    lcc = LifeCycleCORBASSL()
+    # create a FactoryServer Container servant
+    import KernelContainer
+    KernelContainer.myContainer()
+    # activate poaManager to accept co-localized CORBA calls.
+    from KernelSDS import GetDSMInstance
+    import sys
+    if hasattr(sys, 'argv'):
+      argv = sys.argv
+    else:
+      argv = ['']
+    dsm = GetDSMInstance(argv)
+    # esm inherits from SALOME_CPythonHelper singleton already initialized by GetDSMInstance
+    # esm inherits also from SALOME_ResourcesManager creation/initialization (concerning SingleThreadPOA POA) when KernelLauncher.GetContainerManager() has been called
+    esm = KernelLauncher.GetExternalServer()
+    # idem for logm
+    logm = KernelLauncher.myLogManager()
+    type(logm).NaiveFetch = LogManagerNaiveFetch
+    type(logm).Fetch = LogManagerFetch
+    type(logm).DumpInFile = LogManagerDumpInFile
+    type(logm).LaunchMonitoringDumpFile = LogManagerLaunchMonitoringDumpFile
+    type(logm).FinalFetchBeforeDying = LogManagerFinalFetchBeforeDying
+    type(logm).GetLatestMonitoringDumpFile = LogManagerGetLatestMonitoringDumpFile
+    type(logm).DumpIORInFile = LogManagerDumpIORInFile
+    #
+    import KernelLogger
+    naming_service.Register(KernelLogger.myLogger(),"/Logger")
+    #
+    from NamingService import NamingService
+    if iorfakensfile is not None:
+        with open(iorfakensfile,"w") as iorfakensf:
+            iorfakensf.write(NamingService.IOROfNS())
+    
+CM_NAME_IN_NS = "/ContainerManager"
+RM_NAME_IN_NS = "/ResourcesManager"
+DSM_NAME_IN_NS = "/DataServerManager"
+ESM_NAME_IN_NS = "/ExternalServers"
+LOGM_NAME_IN_NS = "/LogManager"
 
-    :param theStudyId: the study Id (optional argument)
-           0      : create a new study (default).
-           n (>0) : try connection to study with Id = n, or create a new one
-                      if study not found.
+def salome_init_without_session_attached(path=None, embedded=False):
+    """
+    Configuration SSL inside a python interpretor launched in the SALOME_Container_No_NS_Serv.
+    In this configuration, a local FakeNamingService is created and remote objects are stored in it.
+    lcc is pointing to the FakeNamingService above.
     """
-    global myStudyId, myStudy, myStudyName
-    myStudyId, myStudy, myStudyName =salome_study.setCurrentStudyId(theStudyId)
+    salome_init_without_session_common(path,embedded)
+    global lcc,cm,dsm,esm,rm,logm
+    import CORBA
+    orb=CORBA.ORB_init([''])
+    import Engines
+    import KernelBasis
+    nsAbroad = orb.string_to_object( KernelBasis.getIOROfEmbeddedNS() )
+    import SALOME
+    cm = orb.string_to_object( nsAbroad.Resolve(CM_NAME_IN_NS).decode() )
+    type(cm).SetOverrideEnvForContainersSimple = ContainerManagerSetOverrideEnvForContainersSimple
+    naming_service.Register(cm,CM_NAME_IN_NS)
+    rm = orb.string_to_object( nsAbroad.Resolve(RM_NAME_IN_NS).decode() )
+    naming_service.Register(rm,RM_NAME_IN_NS)
+    #
+    from LifeCycleCORBA import LifeCycleCORBASSL
+    lcc = LifeCycleCORBASSL()
+    dsm = orb.string_to_object( nsAbroad.Resolve(DSM_NAME_IN_NS).decode() )
+    naming_service.Register(dsm,DSM_NAME_IN_NS)
+    #
+    esm = orb.string_to_object( nsAbroad.Resolve(ESM_NAME_IN_NS).decode() )
+    naming_service.Register(esm,ESM_NAME_IN_NS)
+    #
+    logm = orb.string_to_object( nsAbroad.Resolve(LOGM_NAME_IN_NS).decode() )
+    naming_service.Register(logm,LOGM_NAME_IN_NS)
 
-salome_initial=1
-def salome_init(theStudyId=0,embedded=0):
+def salome_init_with_session(path=None, embedded=False):
     """
-    Performs only once SALOME general purpose intialisation for scripts.
-    optional argument : theStudyId
-      When in embedded interpreter inside IAPP, theStudyId is not used
-      When used without GUI (external interpreter)
-        0      : create a new study (default).
-        n (>0) : try connection to study with Id = n, or create a new one
-                 if study not found.
-                 If study creation, its Id may be different from theStudyId !
+    Performs only once SALOME general purpose initialisation for scripts.
     Provides:
     orb             reference to CORBA
     lcc             a LifeCycleCorba instance
     naming_service  a naming service instance
     cm              reference to the container manager
+    esm             reference to external server manager
+    dsm             reference to shared dataserver manager
+    modulcat        reference to modulecatalog instance
     sg              access to SALOME GUI (when linked with IAPP GUI)
-    myStudyManager  the study manager
-    myStudyId       active study identifier
     myStudy         active study itself (CORBA reference)
     myStudyName     active study name
     """
     global salome_initial
-    global orb, lcc, naming_service, cm
+    global orb, lcc, naming_service, cm, esm, dsm, modulcat
     global sg
-    global myStudyManager, myStudyId, myStudy, myStudyName
-
+    global myStudy, myStudyName
+    import KernelBasis
+    KernelBasis.setSSLMode(False)
     try:
         if salome_initial:
-            salome_initial=0
+            salome_initial=False
             sg = salome_iapp_init(embedded)
-            orb, lcc, naming_service, cm = salome_kernel_init()
-            myStudyManager, myStudyId, myStudy, myStudyName = salome_study_init(theStudyId)
+            orb, lcc, naming_service, cm, esm, dsm, modulcat = salome_kernel_init()
+            myStudy, myStudyName = salome_study_init(path)
             pass
         pass
     except RuntimeError as inst:
@@ -229,29 +355,251 @@ def salome_init(theStudyId=0,embedded=0):
         import time
         time.sleep(0.2)
         x = inst
-        print("salome.salome_init():", x)
+        print("salome.salome_init_with_session():", x)
         print("""
         ============================================
         May be there is no running SALOME session
-        salome.salome_init() is intented to be used
+        salome.salome_init() is intended to be used
         within an already running session
         ============================================
         """)
         raise
     
 def salome_close():
-    global salome_initial, myStudy, myStudyId, myStudyName
+    global salome_initial, myStudy, myStudyName, lcc
     try:
-        # study can be closed either from GUI or directly with salome.myStudy.Close()
-        myStudy.Close()
-    except:
+        # study can be clear either from GUI or directly with salome.myStudy.Clear()
+        myStudy.Clear()
+    except Exception:
         pass
-    salome_initial=1
+    salome_initial=True
     salome_iapp_close()
     salome_study_close()
-    myStudyId, myStudy, myStudyName=None,None,None
+    myStudy, myStudyName = None, None
+    lcc = None # to salome_init to rebuild all in case of salome_init after salome_close
+    import KernelBasis
+    if KernelBasis.getSSLMode() and not KernelBasis.getGUIMode():
+        import KernelDS
+        KernelDS.KillGlobalSessionInstance()
+        import KernelSDS
+        KernelSDS.KillCPythonHelper()
+    pass
+
+def salome_NS():
+    import CORBA
+    import CosNaming
+    orb = CORBA.ORB_init()
+    ns0 = orb.resolve_initial_references("NameService")
+    return ns0._narrow(CosNaming.NamingContext)
+
+def salome_walk_on_containers(ns,root):
+    import CosNaming
+    it = ns.list(0)[1]
+    if not it:
+        return
+    cont = True
+    while cont:
+        cont,obj = it.next_one()
+        if cont:
+            if obj.binding_name[0].kind == "object":
+                import Engines
+                corbaObj = ns.resolve(obj.binding_name)
+                if isinstance(corbaObj,Engines._objref_Container):
+                    yield corbaObj,(root,obj.binding_name[0].id)
+            else:
+                father = ns.resolve([obj.binding_name[0]])
+                for elt,elt2 in salome_walk_on_containers(father,root+[obj.binding_name[0].id]):
+                    yield elt,elt2
+            pass
+        pass
     pass
 
+def salome_shutdown_containers_with_session():
+    salome_init()
+    ns=salome_NS()
+    li = [elt for elt in salome_walk_on_containers(ns,[""])]
+    print("Number of containers in NS : {}".format(len(li)))
+    for cont,(root,cont_name) in li:
+        try:
+            cont.Shutdown()
+        except Exception:
+            pass
+        ref_in_ns = "/".join(root+[cont_name])
+        naming_service.Destroy_Name(ref_in_ns)
+    print("Number of containers in NS after clean : {}".format( len( list(salome_walk_on_containers(ns,[""])) )))
+
+def retrieve_containers_in_ns():
+    return [elt for elt in naming_service.repr() if "/Containers/" == elt[:12]]
+
+def get_all_containers():
+    containersEntries = retrieve_containers_in_ns()
+    return [naming_service.Resolve(containerEntry) for containerEntry in containersEntries]
+    
+def salome_shutdown_containers_without_session():
+    for cont in get_all_containers():
+        try:
+            cont.Shutdown()
+        except:
+            pass
+
+def salome_shutdown_containers():
+    import KernelBasis
+    if KernelBasis.getSSLMode():
+        salome_shutdown_containers_without_session()
+    else:
+        salome_shutdown_containers_with_session()
+
+class SessionContextManager:
+    def __enter__(self):
+        standalone()
+        salome_init()
+    def __exit__(self, type, value, traceback):
+        salome_close()
+
+def ContainerManagerSetOverrideEnvForContainersSimple(self,env):
+    envEff = [ Engines.KeyValPairString(key=k,val=v) for k,v in env ]
+    return self.SetOverrideEnvForContainers( envEff )
+
+def LogManagerNaiveFetch(self):
+    """
+    Fetch data from server with multiple CORBA invokations.
+    """
+    import SALOME_ContainerHelper
+    return [SALOME_ContainerHelper.ContainerLogInfoClt(elt) for elt in self.listOfContainerLogs()]
+
+def LogManagerFetch(self,clearMemory = False):
+    """
+    Fetch data from server in one shot mode.
+    """
+    from SALOME_ContainerHelper import unserializeLogManager
+    return unserializeLogManager( self.getAllStruct(clearMemory) )
+
+def LogManagerDumpInFile(self,fileName,clearMemory = False):
+    with open(fileName,"wb") as f:
+        f.write( self.getAllStruct( clearMemory ) )
+
+
+class LogManagerLaunchMonitoringFileCtxMgr:
+    def __init__(self, intervalInMs, outFileName):
+        self._interval_in_ms = intervalInMs
+        self._out_filename = outFileName
+        self._monitoring_params = None
+    def __enter__(self):
+        import salome
+        self._monitoring_params = salome.logm.LaunchMonitoringDumpFile(self._interval_in_ms, self._out_filename)
+        return self._monitoring_params
+    def __exit__(self,exctype, exc, tb):
+        import SALOME_PyNode
+        import salome
+        SALOME_PyNode.StopMonitoring( self._monitoring_params )
+        salome.logm.GetLatestMonitoringDumpFile()
+        pass
+
+def LogManagerLaunchMonitoringDumpFile(self, intervalInMs, outFileName):
+    """
+    This method loops indefinitely every intervalInMs milliseconds to dump the singleton 
+    content of perf log stored in salome.logm.
+    This method runs in a dedicated subprocess that can be killed at any time.
+    So subprocess code must deal with.
+
+    See also LogManagerGetLatestMonitoringDumpFile
+    """
+    global orb,logm
+    ior = orb.object_to_string( logm )
+    import os
+    outFileName2 = os.path.abspath( os.path.expanduser(outFileName) )
+    import tempfile
+    import logging
+    import SALOME_PyNode
+    import KernelBasis
+    # outFileNameSave stores the content of outFileName during phase of dumping
+    with tempfile.NamedTemporaryFile(prefix=os.path.basename(outFileName2),dir=os.path.dirname(outFileName2)) as f:
+      outFileNameSave = f.name
+    with tempfile.NamedTemporaryFile(prefix="htopmain_",suffix=".py") as f:
+      tempPyFile = f.name
+    with open(tempPyFile,"w") as f:
+        f.write("""import Engines
+import os
+import shutil
+import CORBA
+import time
+orb=CORBA.ORB_init([''], CORBA.ORB_ID)
+logm = orb.string_to_object("{ior}")
+outFileName = "{outFileName}"
+outFileNameSave = "{outFileNameSave}"
+logm.setFileNamePairOfLogger(outFileName, outFileNameSave )
+import salome
+while(True):
+  if os.path.exists( outFileName ):
+    shutil.copy(outFileName,outFileNameSave)
+    logm.versionB_IsTheLatestValidVersion()
+  salome.LogManagerDumpInFile(logm,outFileName)
+  logm.versionA_IsTheLatestValidVersion()
+  time.sleep( {intervalInMs} / 1000.0 )
+""".format( **locals()))
+    logging.debug( "File for monitoring dump file : {}".format(tempPyFile) )
+    pyFileName = SALOME_PyNode.FileDeleter( tempPyFile )
+    pid = KernelBasis.LaunchMonitoring( tempPyFile )
+    return SALOME_PyNode.MonitoringInfo(pyFileName,intervalInMs,None,pid)
+
+def LogManagerDumpIORInFile(self, iorFileName):
+    global logm
+    with open(iorFileName,"w") as f:
+        f.write( orb.object_to_string( logm ) )
+
+def LogManagerLoadFromFile(fileName):
+    from SALOME_ContainerHelper import unserializeLogManager
+    with open(fileName,"rb") as f:
+        data = f.read()
+    return unserializeLogManager( data )
+
+def LogManagerLoadFromIORFile( iorFile ):
+    global orb
+    def LoadAndWrite(logm,tempFileName):
+        import SALOME_PyNode
+        logm.putStructInFileAtomic( False, tempFileName )
+        tempFileAuto = SALOME_PyNode.FileDeleter( tempFileName )
+        ret = LogManagerLoadFromFile( tempFileAuto.filename )
+        return ret
+    with open(iorFile,"r") as f:
+        ior = f.read()
+    import Engines
+    import tempfile
+    salome_init_without_session()
+    logm = orb.string_to_object( ior )
+    with tempfile.NamedTemporaryFile(dir=os.path.expanduser("~")) as f:
+        tempFileName = f.name
+    return LoadAndWrite( logm, tempFileName )
+
+def LogManagerFinalFetchBeforeDying(self):
+    import shutil
+    a,b = self.getFileNamePairOfLogger()
+    self.DumpInFile( b )
+    shutil.move( b, a)
+
+def LogManagerGetLatestMonitoringDumpFile(self):
+    import shutil
+    import logging
+    a,b = self.getFileNamePairOfLogger()
+    if a=="" or b=="":
+        return ""
+    if a == b:
+        return a
+    lastVersion = self.getLastVersionOfFileNameLogger()
+    if lastVersion == a:
+        logging.debug("LogManagerGetLatestMonitoringDumpFile SITUATION A")
+        if os.path.exists( b ):
+            os.remove( b )
+        self.FinalFetchBeforeDying()
+        return a
+    if lastVersion == b:
+        logging.debug("LogManagerGetLatestMonitoringDumpFile SITUATION B")
+        if os.path.exists( b ):
+            shutil.move( b, a)
+        self.FinalFetchBeforeDying()
+        return a
+    logging.warning("in LogManagerGetLatestMonitoringDumpFile an unexpected situation araises.")
+    return ""
 
 #to expose all objects to pydoc
-__all__=dir()
+__all__ = dir()