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