]> SALOME platform Git repositories - modules/yacs.git/blob - src/runtime/DistributedPythonNode.cxx
Salome HOME
Debug + makes the remote python nodes //
[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 #include "SalomeHPContainer.hxx"
25 #include "SalomeContainerTmpForHP.hxx"
26 #include "AutoGIL.hxx"
27
28 #include "PythonPorts.hxx"
29 #include "YacsTrace.hxx"
30 #include "PyStdout.hxx"
31
32 using namespace YACS::ENGINE;
33 using namespace std;
34
35 const char DistributedPythonNode::KIND[]="DistPython";
36 const char DistributedPythonNode::IMPL_NAME[]="Python";
37 const char DistributedPythonNode::SALOME_CONTAINER_METHOD_IDL[]="createPyNode";
38
39 Node *DistributedPythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
40 {
41   return new DistributedPythonNode(*this,father);
42 }
43
44 DistributedPythonNode::DistributedPythonNode(const std::string& name):ServerNode(name),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
45 {
46   initMySelf();
47 }
48
49 DistributedPythonNode::DistributedPythonNode(const DistributedPythonNode& other, ComposedNode *father):ServerNode(other,father),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
50 {
51   initMySelf();
52 }
53
54 DistributedPythonNode::~DistributedPythonNode()
55 {
56   AutoGIL agil;
57   Py_DECREF(_context);
58 }
59
60 void DistributedPythonNode::load()
61 {
62   ServerNode::load();
63   {
64     AutoGIL agil;
65     if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
66       {
67         stringstream msg;
68         msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
69         _errorDetails=msg.str();
70         throw Exception(msg.str());
71       }
72     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";
73     PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
74     if(res == NULL)
75       {
76         _errorDetails="";
77         PyObject* new_stderr = newPyStdOut(_errorDetails);
78         PySys_SetObject((char*)"stderr", new_stderr);
79         PyErr_Print();
80         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
81         Py_DECREF(new_stderr);
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         throw Exception("Error during execution");
97       }
98     if(_pyfuncUnser == NULL)
99       {
100         _errorDetails="";
101         PyObject* new_stderr = newPyStdOut(_errorDetails);
102         PySys_SetObject((char*)"stderr", new_stderr);
103         PyErr_Print();
104         PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
105         Py_DECREF(new_stderr);
106         throw Exception("Error during execution");
107       }
108     DEBTRACE( "---------------End PyfuncSerNode::load function---------------" );
109   }
110 }
111
112 void DistributedPythonNode::execute()
113 {
114   YACSTRACE(1,"+++++++++++++++++ DistributedPythonNode::execute: " << getName() << " " << getFname() << " +++++++++++++++++" );
115   {
116     Engines::Container_var objContainer=Engines::Container::_nil();
117     if(!_container)
118       throw Exception("No container specified !");
119     SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(_container));
120     SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(_container));
121     if(containerCast0)
122       objContainer=containerCast0->getContainerPtr(this);
123     else if(containerCast1)
124       {
125         YACS::BASES::AutoCppPtr<SalomeContainerTmpForHP> tmpCont(SalomeContainerTmpForHP::BuildFrom(containerCast1,this));
126         objContainer=tmpCont->getContainerPtr(this);
127       }
128     else
129       throw Exception("Unrecognized type of container ! Salome one is expected !");
130     if(CORBA::is_nil(objContainer))
131       throw Exception("Container corba pointer is NULL !");
132     Engines::PyNode_var pn=objContainer->createPyNode(getName().c_str(),getScript().c_str());
133     //////
134     int pos=0;
135     PyObject* ob;
136     if(!_pyfuncSer)
137       throw Exception("DistributedPythonNode badly loaded");
138     Engines::pickledArgs *serializationInputCorba(0);
139     PyObject *args(0);
140     {
141         AutoGIL agil;
142
143         DEBTRACE( "---------------DistributedPythonNode::inputs---------------" );
144         args = PyTuple_New(getNumberOfInputPorts()) ;
145         list<InputPort *>::iterator iter2;
146         for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
147           {
148             InputPyPort *p=(InputPyPort *)*iter2;
149             ob=p->getPyObj();
150             Py_INCREF(ob);
151             PyTuple_SetItem(args,pos,ob);
152             pos++;
153           }
154         PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
155         std::string serializationInputC=PyString_AsString(serializationInput);
156         serializationInputCorba=new Engines::pickledArgs;
157         int len=serializationInputC.length();
158         serializationInputCorba->length(serializationInputC.length());
159         for(int i=0;i<serializationInputC.length();i++)
160           (*serializationInputCorba)[i]=serializationInputC[i];
161     }
162     //serializationInputCorba[serializationInputC.length()]='\0';
163     DEBTRACE( "-----------------DistributedPythonNode starting remote python invocation-----------------" );
164     Engines::pickledArgs *resultCorba;
165     try
166     {
167         resultCorba=pn->execute(getFname().c_str(),*serializationInputCorba);
168     }
169     catch(...)
170     {
171         std::string msg="Exception on remote python invocation";
172         _errorDetails=msg;
173         throw Exception(msg);
174     }
175     DEBTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
176     //
177     delete serializationInputCorba;
178     char *resultCorbaC=new char[resultCorba->length()+1];
179     resultCorbaC[resultCorba->length()]='\0';
180     for(int i=0;i<resultCorba->length();i++)
181       resultCorbaC[i]=(*resultCorba)[i];
182     delete resultCorba;
183     {
184       AutoGIL agil;
185       args = PyTuple_New(1);
186       PyObject* resultPython=PyString_FromString(resultCorbaC);
187       delete [] resultCorbaC;
188       PyTuple_SetItem(args,0,resultPython);
189       PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
190       DEBTRACE( "-----------------DistributedPythonNode::outputs-----------------" );
191       int nres=1;
192       if(finalResult == Py_None)
193         nres=0;
194       else if(PyTuple_Check(finalResult))
195         nres=PyTuple_Size(finalResult);
196
197       if(getNumberOfOutputPorts() != nres)
198         {
199           std::string msg="Number of output arguments : Mismatch between definition and execution";
200           Py_DECREF(finalResult);
201           _errorDetails=msg;
202           throw Exception(msg);
203         }
204
205       pos=0;
206       list<OutputPort *>::iterator iter;
207       try
208       {
209           for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
210             {
211               OutputPyPort *p=(OutputPyPort *)*iter;
212               DEBTRACE( "port name: " << p->getName() );
213               DEBTRACE( "port kind: " << p->edGetType()->kind() );
214               DEBTRACE( "port pos : " << pos );
215               if(PyTuple_Check(finalResult))ob=PyTuple_GetItem(finalResult,pos) ;
216               else ob=finalResult;
217               DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
218               p->put(ob);
219               pos++;
220             }
221       }
222       catch(ConversionException& ex)
223       {
224           Py_DECREF(finalResult);
225           _errorDetails=ex.what();
226           throw;
227       }
228     }
229   }
230   DEBTRACE( "++++++++++++++ End DistributedPythonNode::execute: " << getName() << " ++++++++++++++++++++" );
231 }
232
233 std::string DistributedPythonNode::getEffectiveKindOfServer() const
234 {
235   return "Salome";
236 }
237
238 std::string DistributedPythonNode::getKind() const
239 {
240   //! not a bug : this is to use classical python port translators.
241   return PythonNode::KIND;
242 }
243
244 ServerNode *DistributedPythonNode::createNode(const std::string& name) const
245 {
246   ServerNode *ret=new DistributedPythonNode(name);
247   ret->setContainer(_container);
248   return ret;
249 }
250
251 void DistributedPythonNode::initMySelf()
252 {
253   _implementation = DistributedPythonNode::IMPL_NAME;
254   AutoGIL agil;
255   _context=PyDict_New();
256 }
257
258 void DistributedPythonNode::dealException(CORBA::Exception *exc, const char *method, const char *ref)
259 {
260   if( exc )
261     {
262       DEBTRACE( "An exception was thrown!" );
263       DEBTRACE( "The raised exception is of Type:" << exc->_name() );
264
265       CORBA::SystemException* sysexc;
266       sysexc=CORBA::SystemException::_downcast(exc);
267       if(sysexc != NULL)
268         {
269           // It's a SystemException
270           DEBTRACE( "minor code: " << sysexc->minor() );
271           DEBTRACE( "completion code: " << sysexc->completed() );
272           std::string text="Execution problem: ";
273           std::string excname=sysexc->_name();
274           if(excname == "BAD_OPERATION")
275             {
276               text=text+"bad operation detected";
277             }
278           else if(excname == "MARSHAL" && sysexc->minor() == omni::MARSHAL_PassEndOfMessage)
279             {
280               text=text+"probably an error in arguments of service '" + method + "' from component '" +ref+ "'";
281             }
282           else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalResults)
283             {
284               text=text+"probably an error in output arguments of service '" + method + "' from component '" +ref+ "'";
285             }
286           else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalArguments)
287             {
288               text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
289             }
290           else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_WaitingForReply)
291             {
292               text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
293             }
294           else
295             {
296               DEBTRACE(sysexc->NP_minorString() );
297               text=text+"System Exception "+ excname;
298             }
299           _errorDetails=text;
300           throw Exception(text);
301         }
302
303       // Not a System Exception
304       CORBA::UnknownUserException* userexc;
305       userexc=CORBA::UnknownUserException::_downcast(exc);
306       if(userexc != NULL)
307         {
308           CORBA::Any anyExcept = userexc->exception(); 
309
310           const SALOME::SALOME_Exception* salexc;
311           if(anyExcept >>= salexc)
312             {
313               DEBTRACE("SALOME_Exception: "<< salexc->details.sourceFile);
314               DEBTRACE("SALOME_Exception: "<<salexc->details.lineNumber);
315               _errorDetails=salexc->details.text;
316               throw Exception("Execution problem: Salome Exception occurred" + getErrorDetails() );
317             }
318           std::string msg="Execution problem: User Exception occurred";
319           _errorDetails=msg;
320           throw Exception(msg);
321         }
322       std::string msg="Execution problem";
323       _errorDetails=msg;
324       throw Exception(msg);
325     }
326 }