1 // Copyright (C) 2006-2016 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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"
28 #include "PythonPorts.hxx"
29 #include "YacsTrace.hxx"
30 #include "PyStdout.hxx"
32 using namespace YACS::ENGINE;
35 const char DistributedPythonNode::KIND[]="DistPython";
36 const char DistributedPythonNode::IMPL_NAME[]="Python";
37 const char DistributedPythonNode::SALOME_CONTAINER_METHOD_IDL[]="createPyNode";
39 Node *DistributedPythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
41 return new DistributedPythonNode(*this,father);
44 DistributedPythonNode::DistributedPythonNode(const std::string& name):ServerNode(name),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
49 DistributedPythonNode::DistributedPythonNode(const DistributedPythonNode& other, ComposedNode *father):ServerNode(other,father),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
54 DistributedPythonNode::~DistributedPythonNode()
60 void DistributedPythonNode::load()
62 bool isContAlreadyStarted(false);
64 isContAlreadyStarted=_container->isAlreadyStarted(this);
68 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
71 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
72 _errorDetails=msg.str();
73 throw Exception(msg.str());
75 const char picklizeScript[]="import pickle\ndef pickleForDistPyth2009(*args,**kws):\n return pickle.dumps((args,kws),-1)\n\ndef unPickleForDistPyth2009(st):\n args=pickle.loads(st)\n return args\n";
76 PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
80 PyObject* new_stderr = newPyStdOut(_errorDetails);
81 PySys_SetObject((char*)"stderr", new_stderr);
83 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
84 Py_DECREF(new_stderr);
85 throw Exception("Error during execution");
89 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
90 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
91 if(_pyfuncSer == NULL)
94 PyObject* new_stderr = newPyStdOut(_errorDetails);
95 PySys_SetObject((char*)"stderr", new_stderr);
97 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
98 Py_DECREF(new_stderr);
99 throw Exception("Error during execution");
101 if(_pyfuncUnser == NULL)
104 PyObject* new_stderr = newPyStdOut(_errorDetails);
105 PySys_SetObject((char*)"stderr", new_stderr);
107 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
108 Py_DECREF(new_stderr);
109 throw Exception("Error during execution");
112 Engines::Container_var objContainer=Engines::Container::_nil();
114 throw Exception("No container specified !");
115 SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(_container));
116 SalomeHPContainerBase *containerCast1(dynamic_cast<SalomeHPContainerBase *>(_container));
118 objContainer=containerCast0->getContainerPtr(this);
119 else if(containerCast1)
121 objContainer=containerCast1->getContainerPtr(this);
124 throw Exception("Unrecognized type of container ! Salome one is expected !");
125 if(CORBA::is_nil(objContainer))
126 throw Exception("Container corba pointer is NULL !");
130 if(containerCast0 || !isContAlreadyStarted)
132 _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
136 Engines::PyNode_var dftPyScript(objContainer->getDefaultPyNode(getName().c_str()));
137 if(CORBA::is_nil(dftPyScript))
138 _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
140 _pynode = dftPyScript;
143 catch( const SALOME::SALOME_Exception& ex )
145 std::string msg="Exception on remote python node creation ";
147 msg += ex.details.text.in();
149 throw Exception(msg);
152 if(CORBA::is_nil(_pynode))
153 throw Exception("In DistributedPythonNode the ref in NULL ! ");
156 DEBTRACE( "---------------End PyfuncSerNode::load function---------------" );
160 void DistributedPythonNode::execute()
162 YACSTRACE(1,"+++++++++++++++++ DistributedPythonNode::execute: " << getName() << " " << getFname() << " +++++++++++++++++" );
166 throw Exception("DistributedPythonNode badly loaded");
167 Engines::pickledArgs *serializationInputCorba(0);
172 DEBTRACE( "---------------DistributedPythonNode::inputs---------------" );
173 args = PyTuple_New(getNumberOfInputPorts()) ;
175 for(list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
177 InputPyPort *p=(InputPyPort *)*iter2;
180 PyTuple_SetItem(args,pos,ob);
182 PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
183 Py_ssize_t len = PyBytes_Size(serializationInput);
184 char* serializationInputC = PyBytes_AsString(serializationInput);
185 //int ret = PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len);
186 serializationInputCorba=new Engines::pickledArgs;
187 serializationInputCorba->length(len+1);
188 for(int i=0;i<len+1;i++)
189 (*serializationInputCorba)[i]=serializationInputC[i];
190 Py_DECREF(serializationInput);
192 //serializationInputCorba[serializationInputC.length()]='\0';
193 DEBTRACE( "-----------------DistributedPythonNode starting remote python invocation-----------------" );
194 Engines::pickledArgs *resultCorba;
197 resultCorba=_pynode->execute(getFname().c_str(),*serializationInputCorba);
201 std::string msg="Exception on remote python invocation";
203 throw Exception(msg);
205 DEBTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
207 delete serializationInputCorba;
208 char *resultCorbaC=new char[resultCorba->length()+1];
209 resultCorbaC[resultCorba->length()]='\0';
210 for(int i=0;i<resultCorba->length();i++)
211 resultCorbaC[i]=(*resultCorba)[i];
212 int lenResCorba=resultCorba->length();
216 args = PyTuple_New(1);
217 //PyObject* resultPython=PyBytes_FromString(resultCorbaC);
218 PyObject* resultPython=PyBytes_FromStringAndSize(resultCorbaC,lenResCorba);
219 delete [] resultCorbaC;
220 PyTuple_SetItem(args,0,resultPython);
221 PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
222 DEBTRACE( "-----------------DistributedPythonNode::outputs-----------------" );
223 if(finalResult == NULL)
225 std::stringstream msg;
226 msg << "Conversion with pickle of output ports failed !";
227 msg << " : " << __FILE__ << ":" << __LINE__;
228 _errorDetails=msg.str();
229 throw YACS::ENGINE::ConversionException(msg.str());
232 if(finalResult == Py_None)
234 else if(PyTuple_Check(finalResult))
235 nres=PyTuple_Size(finalResult);
237 if(getNumberOfOutputPorts() != nres)
239 std::string msg="Number of output arguments : Mismatch between definition and execution";
240 Py_DECREF(finalResult);
242 throw Exception(msg);
247 for(list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
249 OutputPyPort *p=(OutputPyPort *)*iter;
250 DEBTRACE( "port name: " << p->getName() );
251 DEBTRACE( "port kind: " << p->typeName() );
252 DEBTRACE( "port pos : " << pos );
253 if(PyTuple_Check(finalResult))ob=PyTuple_GetItem(finalResult,pos) ;
255 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
259 catch(ConversionException& ex)
261 Py_DECREF(finalResult);
262 _errorDetails=ex.what();
266 DEBTRACE( "++++++++++++++ End DistributedPythonNode::execute: " << getName() << " ++++++++++++++++++++" );
269 std::string DistributedPythonNode::getEffectiveKindOfServer() const
274 std::string DistributedPythonNode::getKind() const
276 //! not a bug : this is to use classical python port translators.
277 return PythonNode::KIND;
280 ServerNode *DistributedPythonNode::createNode(const std::string& name) const
282 ServerNode *ret=new DistributedPythonNode(name);
283 ret->setContainer(_container);
287 void DistributedPythonNode::initMySelf()
289 _implementation = DistributedPythonNode::IMPL_NAME;
291 _context=PyDict_New();
294 void DistributedPythonNode::dealException(CORBA::Exception *exc, const char *method, const char *ref)
298 DEBTRACE( "An exception was thrown!" );
299 DEBTRACE( "The raised exception is of Type:" << exc->_name() );
301 CORBA::SystemException* sysexc;
302 sysexc=CORBA::SystemException::_downcast(exc);
305 // It's a SystemException
306 DEBTRACE( "minor code: " << sysexc->minor() );
307 DEBTRACE( "completion code: " << sysexc->completed() );
308 std::string text="Execution problem: ";
309 std::string excname=sysexc->_name();
310 if(excname == "BAD_OPERATION")
312 text=text+"bad operation detected";
314 else if(excname == "MARSHAL" && sysexc->minor() == omni::MARSHAL_PassEndOfMessage)
316 text=text+"probably an error in arguments of service '" + method + "' from component '" +ref+ "'";
318 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalResults)
320 text=text+"probably an error in output arguments of service '" + method + "' from component '" +ref+ "'";
322 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalArguments)
324 text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
326 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_WaitingForReply)
328 text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
332 DEBTRACE(sysexc->NP_minorString() );
333 text=text+"System Exception "+ excname;
336 throw Exception(text);
339 // Not a System Exception
340 CORBA::UnknownUserException* userexc;
341 userexc=CORBA::UnknownUserException::_downcast(exc);
344 CORBA::Any anyExcept = userexc->exception();
346 const SALOME::SALOME_Exception* salexc;
347 if(anyExcept >>= salexc)
349 DEBTRACE("SALOME_Exception: "<< salexc->details.sourceFile);
350 DEBTRACE("SALOME_Exception: "<<salexc->details.lineNumber);
351 _errorDetails=salexc->details.text;
352 throw Exception("Execution problem: Salome Exception occurred" + getErrorDetails() );
354 std::string msg="Execution problem: User Exception occurred";
356 throw Exception(msg);
358 std::string msg="Execution problem";
360 throw Exception(msg);