1 // Copyright (C) 2006-2014 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"
25 #include "PythonPorts.hxx"
26 #include "YacsTrace.hxx"
27 #include "PyStdout.hxx"
29 using namespace YACS::ENGINE;
32 const char DistributedPythonNode::KIND[]="DistPython";
33 const char DistributedPythonNode::IMPL_NAME[]="Python";
34 const char DistributedPythonNode::SALOME_CONTAINER_METHOD_IDL[]="createPyNode";
36 Node *DistributedPythonNode::simpleClone(ComposedNode *father, bool editionOnly) const
38 return new DistributedPythonNode(*this,father);
41 DistributedPythonNode::DistributedPythonNode(const std::string& name):ServerNode(name),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
46 DistributedPythonNode::DistributedPythonNode(const DistributedPythonNode& other, ComposedNode *father):ServerNode(other,father),_context(0),_pyfuncSer(0),_pyfuncUnser(0)
51 DistributedPythonNode::~DistributedPythonNode()
53 PyGILState_STATE gstate = PyGILState_Ensure();
55 PyGILState_Release(gstate);
58 void DistributedPythonNode::load()
61 PyGILState_STATE gstate = PyGILState_Ensure();
62 if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
65 msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
66 PyGILState_Release(gstate);
67 _errorDetails=msg.str();
68 throw Exception(msg.str());
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);
75 PyObject* new_stderr = newPyStdOut(_errorDetails);
76 PySys_SetObject((char*)"stderr", new_stderr);
78 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
79 Py_DECREF(new_stderr);
81 PyGILState_Release(gstate);
82 throw Exception("Error during execution");
86 _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
87 _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
88 if(_pyfuncSer == NULL)
91 PyObject* new_stderr = newPyStdOut(_errorDetails);
92 PySys_SetObject((char*)"stderr", new_stderr);
94 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
95 Py_DECREF(new_stderr);
97 PyGILState_Release(gstate);
98 throw Exception("Error during execution");
100 if(_pyfuncUnser == NULL)
103 PyObject* new_stderr = newPyStdOut(_errorDetails);
104 PySys_SetObject((char*)"stderr", new_stderr);
106 PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
107 Py_DECREF(new_stderr);
109 PyGILState_Release(gstate);
110 throw Exception("Error during execution");
112 DEBTRACE( "---------------End PyfuncSerNode::load function---------------" );
113 PyGILState_Release(gstate);
116 void DistributedPythonNode::execute()
118 YACSTRACE(1,"+++++++++++++++++ DistributedPythonNode::execute: " << getName() << " " << getFname() << " +++++++++++++++++" );
120 Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(0);
121 Engines::PyNode_var pn=objContainer->createPyNode(getName().c_str(),getScript().c_str());
126 throw Exception("DistributedPythonNode badly loaded");
127 PyGILState_STATE gstate = PyGILState_Ensure();
129 DEBTRACE( "---------------DistributedPythonNode::inputs---------------" );
130 PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
131 list<InputPort *>::iterator iter2;
132 for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
134 InputPyPort *p=(InputPyPort *)*iter2;
137 PyTuple_SetItem(args,pos,ob);
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;
152 resultCorba=pn->execute(getFname().c_str(),*serializationInputCorba);
156 std::string msg="Exception on remote python invocation";
157 PyGILState_Release(gstate);
159 throw Exception(msg);
161 DEBTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
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];
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-----------------" );
176 if(finalResult == Py_None)
178 else if(PyTuple_Check(finalResult))
179 nres=PyTuple_Size(finalResult);
181 if(getNumberOfOutputPorts() != nres)
183 std::string msg="Number of output arguments : Mismatch between definition and execution";
184 Py_DECREF(finalResult);
185 PyGILState_Release(gstate);
187 throw Exception(msg);
191 list<OutputPort *>::iterator iter;
194 for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
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) ;
202 DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
207 catch(ConversionException& ex)
209 Py_DECREF(finalResult);
210 PyGILState_Release(gstate);
211 _errorDetails=ex.what();
214 PyGILState_Release(gstate);
216 DEBTRACE( "++++++++++++++ End DistributedPythonNode::execute: " << getName() << " ++++++++++++++++++++" );
219 std::string DistributedPythonNode::getEffectiveKindOfServer() const
224 std::string DistributedPythonNode::getKind() const
226 //! not a bug : this is to use classical python port translators.
227 return PythonNode::KIND;
230 ServerNode *DistributedPythonNode::createNode(const std::string& name) const
232 ServerNode *ret=new DistributedPythonNode(name);
233 ret->setContainer(_container);
237 void DistributedPythonNode::initMySelf()
239 _implementation = DistributedPythonNode::IMPL_NAME;
240 PyGILState_STATE gstate=PyGILState_Ensure();
241 _context=PyDict_New();
242 PyGILState_Release(gstate);
245 void DistributedPythonNode::dealException(CORBA::Exception *exc, const char *method, const char *ref)
249 DEBTRACE( "An exception was thrown!" );
250 DEBTRACE( "The raised exception is of Type:" << exc->_name() );
252 CORBA::SystemException* sysexc;
253 sysexc=CORBA::SystemException::_downcast(exc);
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")
263 text=text+"bad operation detected";
265 else if(excname == "MARSHAL" && sysexc->minor() == omni::MARSHAL_PassEndOfMessage)
267 text=text+"probably an error in arguments of service '" + method + "' from component '" +ref+ "'";
269 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalResults)
271 text=text+"probably an error in output arguments of service '" + method + "' from component '" +ref+ "'";
273 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_UnMarshalArguments)
275 text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
277 else if(excname == "COMM_FAILURE" && sysexc->minor() == omni::COMM_FAILURE_WaitingForReply)
279 text=text+"probably an error in input arguments of service '" + method + "' from component '" +ref+ "'";
283 DEBTRACE(sysexc->NP_minorString() );
284 text=text+"System Exception "+ excname;
287 throw Exception(text);
290 // Not a System Exception
291 CORBA::UnknownUserException* userexc;
292 userexc=CORBA::UnknownUserException::_downcast(exc);
295 CORBA::Any anyExcept = userexc->exception();
297 const SALOME::SALOME_Exception* salexc;
298 if(anyExcept >>= salexc)
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() );
305 std::string msg="Execution problem: User Exception occurred";
307 throw Exception(msg);
309 std::string msg="Execution problem";
311 throw Exception(msg);