Salome HOME
0022821: EDF 9434 PARAVIS: Problem with plugins loading when starting a Nth session...
[modules/paravis.git] / src / ENGINE / no_wrap / PVSERVER.py
1 # Copyright (C) 2007-2014  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, or (at your option) any later version.
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 # Author : Adrien Bruneton (CEA)
23 #
24
25 import PVSERVER_ORB__POA
26 import SALOME_ComponentPy
27 import SALOME_DriverPy
28 import SALOMEDS
29 import SALOME
30 import PVSERVER_utils
31 import subprocess as subp
32 import socket
33 from time import sleep
34 import os
35 #from SALOME_utilities import MESSAGE
36
37 def MESSAGE(m):
38     pass
39     #os.system("echo \"%s\" >> /tmp/paravis_log.txt" % m)
40
41 class PVSERVER_Impl:
42     """ The core implementation (non CORBA, or Study related).
43         See the IDL for the documentation.
44     """
45     MAX_PVSERVER_PORT_TRIES = 1000
46     PVSERVER_DEFAULT_PORT = 11111
47     
48     def __init__(self):
49         self.pvserverPort = -1
50         self.pvserverPop = None  # Popen object from subprocess module
51         self.lastTrace = ""
52         self.isGUIConnected = False  # whether there is an active connection from the GUI.
53         try:
54             import paraview
55             tmp=paraview.__file__
56         except:
57             raise Exception("PVSERVER_Impl.__init__ : \"import paraview\" failed !")
58         # deduce dynamically PARAVIEW_ROOT_DIR from the paraview module location
59         self.PARAVIEW_ROOT_DIR = None
60         ZE_KEY_TO_FIND_PV_ROOT_DIR="lib"
61         li=tmp.split(os.path.sep) ; li.reverse()
62         if ZE_KEY_TO_FIND_PV_ROOT_DIR not in li:
63             raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR,
64                       "PVSERVER_Impl.__init__ : error during dynamic deduction of PARAVIEW_ROOT_DIR : Loc of paraview module is \"%s\" ! \"%s\" is supposed to be the key to deduce it !"%(tmp,ZE_KEY_TO_FIND_PV_ROOT_DIR),
65                       "PVSERVER.py", 0))
66         li=li[li.index("lib")+1:] ; li.reverse()
67         self.PARAVIEW_ROOT_DIR = os.path.sep.join(li)
68
69     """
70     Private. Identify a free port to launch the PVServer. 
71     """
72     def __getFreePort(self, startPort):
73         cnt = 0
74         currPort = startPort
75         while cnt < self.MAX_PVSERVER_PORT_TRIES:
76             try:
77                 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
78                 s.bind(('', currPort))
79                 s.close()
80                 return currPort
81             except socket.error as e:
82                 cnt += 1
83                 currPort += 1
84                 pass
85         raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR,
86                             "[PVSERVER] maximum number of tries to retrieve a free port for the PVServer",
87                             "PVSERVER.py", 0))
88                                            
89     def FindOrStartPVServer( self, port ):
90         MESSAGE("[PVSERVER] FindOrStartPVServer ...")
91         host = "localhost"
92         alive = True
93         if self.pvserverPop is None:
94             alive = False
95         else:
96             # Poll active server to check if still alive
97             self.pvserverPop.poll()
98             if not self.pvserverPop.returncode is None:  # server terminated
99                 alive = False
100         
101         if alive:
102             return "cs://%s:%d" % (host, self.pvserverPort)  
103           
104         # (else) Server not alive, start it:
105         pvServerPath = os.path.join(self.PARAVIEW_ROOT_DIR, 'bin', 'pvserver')
106         opt = []
107         if port <= 0:
108             port = self.__getFreePort(self.PVSERVER_DEFAULT_PORT)
109         self.pvserverPop = subp.Popen([pvServerPath, "--multi-clients", "--server-port=%d" % port])
110         sleep(3)  # Give some time to the server to start up to avoid 
111                   # ugly messages on the client side saying that it cannot connect
112         # Is PID still alive? If yes, consider that the launch was successful
113         self.pvserverPop.poll()
114         if self.pvserverPop.returncode is None:
115             success = True
116             self.pvserverPort = port
117             MESSAGE("[PVSERVER] pvserver successfully launched on port %d" % port)
118         else:
119             raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.INTERNAL_ERROR,
120                             "[PVSERVER] Unable to start PVServer on port %d!" % port,
121                             "PVSERVER.py", 0))
122         return "cs://%s:%d" % (host, self.pvserverPort)
123
124     def StopPVServer( self ):
125         MESSAGE("[PVSERVER] Trying to stop PVServer (sending KILL) ...")
126         if not self.pvserverPop is None:
127             self.pvserverPop.poll()
128             if self.pvserverPop.returncode is None:
129                 # Terminate if still running:
130                 self.pvserverPop.terminate()
131                 MESSAGE("[PVSERVER] KILL signal sent.")
132                 return True
133         MESSAGE("[PVSERVER] Nothing to kill.")
134         return False
135     
136     def PutPythonTraceStringToEngine( self, t ):
137         self.lastTrace = t
138         
139     def GetPythonTraceString(self):
140         return self.lastTrace
141       
142     def SetGUIConnected( self, isConnected ):
143         self.isGUIConnected = isConnected
144         
145     def GetGUIConnected( self ):
146         return self.isGUIConnected
147     
148 class PVSERVER(PVSERVER_ORB__POA.PVSERVER_Gen,
149               SALOME_ComponentPy.SALOME_ComponentPy_i,
150               SALOME_DriverPy.SALOME_DriverPy_i,
151               PVSERVER_Impl):
152     """
153     Construct an instance of PVSERVER module engine.
154     The class PVSERVER implements CORBA interface PVSERVER_Gen (see PVSERVER_Gen.idl).
155     It is inherited from the classes SALOME_ComponentPy_i (implementation of
156     Engines::EngineComponent CORBA interface - SALOME component) and SALOME_DriverPy_i
157     (implementation of SALOMEDS::Driver CORBA interface - SALOME module's engine).
158     """
159     def __init__ ( self, orb, poa, contID, containerName, instanceName, 
160                    interfaceName ):
161         SALOME_ComponentPy.SALOME_ComponentPy_i.__init__(self, orb, poa,
162                     contID, containerName, instanceName, interfaceName, 0)
163         SALOME_DriverPy.SALOME_DriverPy_i.__init__(self, interfaceName)
164         PVSERVER_Impl.__init__(self)
165         #
166         self._naming_service = SALOME_ComponentPy.SALOME_NamingServicePy_i( self._orb )
167         #
168
169     """ Override base class destroy to make sure we try to kill the pvserver
170         before leaving.
171     """
172     def destroy(self):    
173         self.StopPVServer()
174         # Invokes super():
175         SALOME_ComponentPy.destroy(self)
176       
177     """
178     Get version information.
179     """
180     def getVersion( self ):
181         import salome_version
182         return salome_version.getVersion("PARAVIS", True)
183
184     def GetIOR(self):
185         return PVSERVER_utils.getEngineIOR()
186
187     """
188     Create object.
189     """
190     def createObject( self, study, name ):
191         MESSAGE("createObject()")
192         self._createdNew = True # used for getModifiedData method
193         builder = study.NewBuilder()
194         father  = findOrCreateComponent( study )
195         object  = builder.NewObject( father )
196         attr    = builder.FindOrCreateAttribute( object, "AttributeName" )
197         attr.SetValue( name )
198         attr    = builder.FindOrCreateAttribute( object, "AttributeLocalID" )
199         attr.SetValue( PVSERVER_utils.objectID() )
200         pass
201
202     """
203     Dump module data to the Python script.
204     """
205     def DumpPython( self, study, isPublished, isMultiFile ):
206         MESSAGE("dumpPython()") 
207         abuffer = self.GetPythonTraceString().split("\n")
208         if isMultiFile:
209             abuffer       = [ "  " + s for s in abuffer ]
210             abuffer[0:0]  = [ "def RebuildData( theStudy ):" ]
211             abuffer      += [ "  pass" ]
212         abuffer += [ "\0" ]
213         return ("\n".join( abuffer ), 1)
214   
215     """
216     Import file to restore module data
217     """
218     def importData(self, studyId, dataContainer, options):
219       MESSAGE("importData()")
220       # get study by Id
221       obj = self._naming_service.Resolve("myStudyManager")
222       myStudyManager = obj._narrow(SALOMEDS.StudyManager)
223       study = myStudyManager.GetStudyByID(studyId)
224       # create all objects from the imported stream
225       stream = dataContainer.get()
226       for objname in stream.split("\n"):
227         if len(objname) != 0:
228           self.createObject(study, objname)
229       self._createdNew = False # to store the modification of the study information later
230       return ["objects"] # identifier what is in this file
231  
232     def getModifiedData(self, studyId):
233       MESSAGE("getModifiedData()")
234       if self._createdNew:
235         # get study by Id
236         obj = self._naming_service.Resolve("myStudyManager")
237         myStudyManager = obj._narrow(SALOMEDS.StudyManager)
238         study = myStudyManager.GetStudyByID(studyId)
239         # iterate all objects to get their names and store this information in stream
240         stream=""
241         father = study.FindComponent( moduleName() )
242         if father:
243             iter = study.NewChildIterator( father )
244             while iter.More():
245                 name = iter.Value().GetName()
246                 stream += name + "\n"
247                 iter.Next()
248         # store stream to the temporary file to send it in DataContainer
249         dataContainer = SALOME_DataContainerPy_i(stream, "", "objects", False, True)
250         aVar = dataContainer._this()
251         return [aVar]
252       return []