Salome HOME
Merge branch V7_3_1_BR
[modules/yacs.git] / src / runtime / DistributedPythonNode.cxx
1 // Copyright (C) 2006-2014  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "DistributedPythonNode.hxx"
21 #include "RuntimeSALOME.hxx"
22 #include "SalomeContainer.hxx"
23 #include "PythonNode.hxx"
24
25 #include "PythonPorts.hxx"
26 #include "YacsTrace.hxx"
27 #include "PyStdout.hxx"
28
29 using namespace YACS::ENGINE;
30 using namespace std;
31
32 const char DistributedPythonNode::KIND[]="DistPython";
33 const char DistributedPythonNode::IMPL_NAME[]="Python";
34 const char DistributedPythonNode::SALOME_CONTAINER_METHOD_IDL[]="createPyNode";
35
36 Node *DistributedPythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
37 {
38   return new DistributedPythonNode(*this,father);
39 }
40
41 DistributedPythonNode::DistributedPythonNode(const std::string& name):ServerNode(name),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
42 {
43   initMySelf();
44 }
45
46 DistributedPythonNode::DistributedPythonNode(const DistributedPythonNode& other, ComposedNode *father):ServerNode(other,father),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
47 {
48   initMySelf();
49 }
50
51 DistributedPythonNode::~DistributedPythonNode()
52 {
53   PyGILState_STATE gstate = PyGILState_Ensure();
54   Py_DECREF(_context);
55   PyGILState_Release(gstate);
56 }
57
58 void DistributedPythonNode::load()
59 {
60   ServerNode::load();
61   PyGILState_STATE gstate = PyGILState_Ensure();
62   if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
63     {
64       stringstream msg;
65       msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
66       PyGILState_Release(gstate);
67       _errorDetails=msg.str();
68       throw Exception(msg.str());
69     }
70   const char picklizeScript[]="import cPickle\ndef pickleForDistPyth2009(*args,**kws):\n  return cPickle.dumps((args,kws),-1)\n\ndef unPickleForDistPyth2009(st):\n  args=cPickle.loads(st)\n  return args\n";
71   PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
72   if(res == NULL)
73     {
74       _errorDetails="";
75       PyObject* new_stderr = newPyStdOut(_errorDetails);
76       PySys_SetObject((char*)"stderr", new_stderr);
77       PyErr_Print();
78       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
79       Py_DECREF(new_stderr);
80
81       PyGILState_Release(gstate);
82       throw Exception("Error during execution");
83       return;
84     }
85   Py_DECREF(res);
86   _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
87   _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
88   if(_pyfuncSer == NULL)
89     {
90       _errorDetails="";
91       PyObject* new_stderr = newPyStdOut(_errorDetails);
92       PySys_SetObject((char*)"stderr", new_stderr);
93       PyErr_Print();
94       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
95       Py_DECREF(new_stderr);
96
97       PyGILState_Release(gstate);
98       throw Exception("Error during execution");
99     }
100   if(_pyfuncUnser == NULL)
101     {
102       _errorDetails="";
103       PyObject* new_stderr = newPyStdOut(_errorDetails);
104       PySys_SetObject((char*)"stderr", new_stderr);
105       PyErr_Print();
106       PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
107       Py_DECREF(new_stderr);
108
109       PyGILState_Release(gstate);
110       throw Exception("Error during execution");
111     }
112   DEBTRACE( "---------------End PyfuncSerNode::load function---------------" );
113   PyGILState_Release(gstate);
114 }
115
116 void DistributedPythonNode::execute()
117 {
118   YACSTRACE(1,"+++++++++++++++++ DistributedPythonNode::execute: " << getName() << " " << getFname() << " +++++++++++++++++" );
119   {
120     Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
121     Engines::PyNode_var pn=objContainer->createPyNode(getName().c_str(),getScript().c_str());
122     //////
123     int pos=0;
124     PyObject* ob;
125     if(!_pyfuncSer)
126       throw Exception("DistributedPythonNode badly loaded");
127     PyGILState_STATE gstate = PyGILState_Ensure();
128     
129     DEBTRACE( "---------------DistributedPythonNode::inputs---------------" );
130     PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
131     list<InputPort *>::iterator iter2;
132     for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
133       {
134         InputPyPort *p=(InputPyPort *)*iter2;
135         ob=p->getPyObj();
136         Py_INCREF(ob);
137         PyTuple_SetItem(args,pos,ob);
138         pos++;
139       }
140     PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
141     std::string serializationInputC=PyString_AsString(serializationInput);
142     Engines::pickledArgs *serializationInputCorba=new Engines::pickledArgs;
143     int len=serializationInputC.length();
144     serializationInputCorba->length(serializationInputC.length());
145     for(int i=0;i<serializationInputC.length();i++)
146       (*serializationInputCorba)[i]=serializationInputC[i];
147     //serializationInputCorba[serializationInputC.length()]='\0';
148     DEBTRACE( "-----------------DistributedPythonNode starting remote python invocation-----------------" );
149     Engines::pickledArgs *resultCorba;
150     try
151       {
152         resultCorba=pn->execute(getFname().c_str(),*serializationInputCorba);
153       }
154     catch(...)
155       {
156         std::string msg="Exception on remote python invocation";
157         PyGILState_Release(gstate);
158         _errorDetails=msg;
159         throw Exception(msg);
160       }
161     DEBTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
162     //
163     delete serializationInputCorba;
164     char *resultCorbaC=new char[resultCorba->length()+1];
165     resultCorbaC[resultCorba->length()]='\0';
166     for(int i=0;i<resultCorba->length();i++)
167       resultCorbaC[i]=(*resultCorba)[i];
168     delete resultCorba;
169     args = PyTuple_New(1);
170     PyObject* resultPython=PyString_FromString(resultCorbaC);
171     delete [] resultCorbaC;
172     PyTuple_SetItem(args,0,resultPython);
173     PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
174     DEBTRACE( "-----------------DistributedPythonNode::outputs-----------------" );
175     int nres=1;
176     if(finalResult == Py_None)
177       nres=0;
178     else if(PyTuple_Check(finalResult))
179       nres=PyTuple_Size(finalResult);
180     
181     if(getNumberOfOutputPorts() != nres)
182       {
183         std::string msg="Number of output arguments : Mismatch between definition and execution";
184         Py_DECREF(finalResult);
185         PyGILState_Release(gstate);
186         _errorDetails=msg;
187         throw Exception(msg);
188       }
189     
190     pos=0;
191     list<OutputPort *>::iterator iter;
192     try
193       {
194         for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
195           {
196             OutputPyPort *p=(OutputPyPort *)*iter;
197             DEBTRACE( "port name: " << p->getName() );
198             DEBTRACE( "port kind: " << p->edGetType()->kind() );
199             DEBTRACE( "port pos : " << pos );
200             if(PyTuple_Check(finalResult))ob=PyTuple_GetItem(finalResult,pos) ;
201             else ob=finalResult;
202             DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
203             p->put(ob);
204             pos++;
205           }
206       }
207     catch(ConversionException& ex)
208       {
209         Py_DECREF(finalResult);
210         PyGILState_Release(gstate);
211         _errorDetails=ex.what();
212         throw;
213       }
214     PyGILState_Release(gstate);
215   }
216   DEBTRACE( "++++++++++++++ End DistributedPythonNode::execute: " << getName() << " ++++++++++++++++++++" );
217 }
218
219 std::string DistributedPythonNode::getEffectiveKindOfServer() const
220 {
221   return "Salome";
222 }
223
224 std::string DistributedPythonNode::getKind() const
225 {
226   //! not a bug : this is to use classical python port translators.
227   return PythonNode::KIND;
228 }
229
230 ServerNode *DistributedPythonNode::createNode(const std::string& name) const
231 {
232   ServerNode *ret=new DistributedPythonNode(name);
233   ret->setContainer(_container);
234   return ret;
235 }
236
237 void DistributedPythonNode::initMySelf()
238 {
239   _implementation = DistributedPythonNode::IMPL_NAME;
240   PyGILState_STATE gstate=PyGILState_Ensure();
241   _context=PyDict_New();
242   PyGILState_Release(gstate);
243 }
244
245 void DistributedPythonNode::dealException(CORBA::Exception *exc, const char *method, const char *ref)
246 {
247   if( exc )
248     {
249       DEBTRACE( "An exception was thrown!" );
250       DEBTRACE( "The raised exception is of Type:" << exc->_name() );
251
252       CORBA::SystemException* sysexc;
253       sysexc=CORBA::SystemException::_downcast(exc);
254       if(sysexc != NULL)
255         {
256           // It's a SystemException
257           DEBTRACE( "minor code: " << sysexc->minor() );
258           DEBTRACE( "completion code: " << sysexc->completed() );
259           std::string text="Execution problem: ";
260           std::string excname=sysexc->_name();
261           if(excname == "BAD_OPERATION")
262             {
263               text=text+"bad operation detected";
264             }
265           else if(excname == "MARSHAL" && sysexc->minor() == omni::MARSHAL_PassEndOfMessage)
266             {
267               text=text+"probably an error in arguments of service '" + method + "' from component '" +ref+ "'";
268             }
269           else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalResults)
270             {
271               text=text+"probably an error in output arguments of service '" + method + "' from component '" +ref+ "'";
272             }
273           else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalArguments)
274             {
275               text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
276             }
277           else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_WaitingForReply)
278             {
279               text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
280             }
281           else
282             {
283               DEBTRACE(sysexc->NP_minorString() );
284               text=text+"System Exception "+ excname;
285             }
286           _errorDetails=text;
287           throw Exception(text);
288         }
289
290       // Not a System Exception
291       CORBA::UnknownUserException* userexc;
292       userexc=CORBA::UnknownUserException::_downcast(exc);
293       if(userexc != NULL)
294         {
295           CORBA::Any anyExcept = userexc->exception(); 
296
297           const SALOME::SALOME_Exception* salexc;
298           if(anyExcept >>= salexc)
299             {
300               DEBTRACE("SALOME_Exception: "<< salexc->details.sourceFile);
301               DEBTRACE("SALOME_Exception: "<<salexc->details.lineNumber);
302               _errorDetails=salexc->details.text;
303               throw Exception("Execution problem: Salome Exception occurred" + getErrorDetails() );
304             }
305           std::string msg="Execution problem: User Exception occurred";
306           _errorDetails=msg;
307           throw Exception(msg);
308         }
309       std::string msg="Execution problem";
310       _errorDetails=msg;
311       throw Exception(msg);
312     }
313 }