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