Salome HOME
Synchronize adm files
[modules/yacs.git] / src / runtime / RuntimeSALOME.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 //#define REFCNT
21 //
22 #ifdef REFCNT
23 #define private public
24 #define protected public
25 #include <omniORB4/CORBA.h>
26 #include <omniORB4/internal/typecode.h>
27 #include <omniORB4/internal/corbaOrb.h>
28 #endif
29
30 #include "yacsconfig.h"
31 #include "YACS_version.h"
32 #include "RuntimeSALOME.hxx"
33 #include "SALOMEDispatcher.hxx"
34 #include "Proc.hxx"
35 #include "TypeCode.hxx"
36 #include "WhileLoop.hxx"
37 #include "ForLoop.hxx"
38 #include "SalomeOptimizerLoop.hxx"
39 #include "Bloc.hxx"
40 #include "InputPort.hxx"
41 #include "OutputPort.hxx"
42 #include "PresetPorts.hxx"
43 #include "InputDataStreamPort.hxx"
44 #include "OutputDataStreamPort.hxx"
45 #include "SalomeProc.hxx"
46 #include "PyStdout.hxx"
47 //Catalog Loaders
48 #include "SessionCataLoader.hxx"
49
50 //Components
51 #include "CORBAComponent.hxx"
52 #include "SalomeComponent.hxx"
53 #include "SalomePythonComponent.hxx"
54 #include "CppComponent.hxx"
55
56 #include "SalomeContainer.hxx"
57 #include "CppContainer.hxx"
58
59 //Nodes
60 #include "PythonNode.hxx"
61 #include "CORBANode.hxx"
62 #include "XMLNode.hxx"
63 #include "CppNode.hxx"
64 #include "PresetNode.hxx"
65 #include "OutNode.hxx"
66 #include "StudyNodes.hxx"
67 #include "SalomePythonNode.hxx"
68 #include "DistributedPythonNode.hxx"
69
70 //CORBA proxy ports
71 #include "CORBACORBAConv.hxx"
72 #include "CORBAPythonConv.hxx"
73 #include "CORBAXMLConv.hxx"
74 #include "CORBACppConv.hxx"
75 #include "CORBANeutralConv.hxx"
76
77 #include "TypeConversions.hxx"
78 //Python proxy ports
79 #include "PythonCORBAConv.hxx"
80 #include "PythonXMLConv.hxx"
81 #include "PythonCppConv.hxx"
82 #include "PythonNeutralConv.hxx"
83 #include "PythonInitConv.hxx"
84
85 //Neutral proxy ports
86 #include "NeutralCORBAConv.hxx"
87 #include "NeutralPythonConv.hxx"
88 #include "NeutralXMLConv.hxx"
89 #include "NeutralCppConv.hxx"
90 #include "NeutralInitConv.hxx"
91
92 //C++ proxy ports
93 #include "CppCORBAConv.hxx"
94 #include "CppPythonConv.hxx"
95 #include "CppXMLConv.hxx"
96 #include "CppCppConv.hxx"
97 #include "CppNeutralConv.hxx"
98
99 //XML proxy ports
100 #include "XMLCORBAConv.hxx"
101 #include "XMLPythonConv.hxx"
102 #include "XMLCppConv.hxx"
103 #include "XMLNeutralConv.hxx"
104
105 //Calcium specific ports
106 #include "CalStreamPort.hxx"
107
108 #ifdef SALOME_KERNEL
109 #include "SALOME_NamingService.hxx"
110 #include "SALOME_LifeCycleCORBA.hxx"
111 #endif
112   
113 #include <libxml/parser.h>
114 #include <omniORB4/CORBA.h>
115 #include <iostream>
116 #include <sstream>
117 #include <cassert>
118
119 //#define _DEVDEBUG_
120 #include "YacsTrace.hxx"
121
122 using namespace std;
123 using namespace YACS::ENGINE;
124
125 void RuntimeSALOME::setRuntime(long flags, int argc, char* argv[]) // singleton creation (not thread safe!)
126 {
127   if (! Runtime::_singleton)
128     {
129       RuntimeSALOME* r=new RuntimeSALOME(flags, argc, argv);
130       Runtime::_singleton = r;
131       r->initBuiltins();
132     }
133   DEBTRACE("RuntimeSALOME::setRuntime() done !");
134 }
135
136 RuntimeSALOME* YACS::ENGINE::getSALOMERuntime()
137 {
138   YASSERT(Runtime::_singleton);
139   return dynamic_cast< RuntimeSALOME* >(Runtime::_singleton);
140 }
141
142 /**
143  *  Singleton creation, initialize converter map
144  */
145   
146 RuntimeSALOME::RuntimeSALOME()
147 {
148   YASSERT(0);
149 }
150
151 void RuntimeSALOME::initBuiltins()
152 {
153   //Fill the builtin catalog with nodes specific to the runtime
154   std::map<std::string,TypeCode*>& typeMap=_builtinCatalog->_typeMap;
155   std::map<std::string,Node*>& nodeMap=_builtinCatalog->_nodeMap;
156   std::map<std::string,ComposedNode*>& composednodeMap=_builtinCatalog->_composednodeMap;
157   std::map<std::string,ComponentDefinition*>& componentMap=_builtinCatalog->_componentMap;
158   nodeMap["PyFunction"]=new PyFuncNode("PyFunction");
159   nodeMap["PyScript"]=new PythonNode("PyScript");
160   nodeMap["CORBANode"]=new CORBANode("CORBANode");
161   nodeMap["XmlNode"]=new XmlNode("XmlNode");
162   nodeMap["SalomeNode"]=new SalomeNode("SalomeNode");
163   nodeMap["CppNode"]=new CppNode("CppNode");
164   nodeMap["SalomePythonNode"]=new SalomePythonNode("SalomePythonNode");
165   nodeMap["PresetNode"]=new PresetNode("PresetNode");
166   nodeMap["OutNode"]=new OutNode("OutNode");
167   nodeMap["StudyInNode"]=new StudyInNode("StudyInNode");
168   nodeMap["StudyOutNode"]=new StudyOutNode("StudyOutNode");
169   composednodeMap["OptimizerLoop"]=createOptimizerLoop("OptimizerLoop","","",true);
170   typeMap["dblevec"]= createSequenceTc("dblevec","dblevec",_tc_double);
171   typeMap["intvec"]= createSequenceTc("intvec","intvec",_tc_int);
172   typeMap["stringvec"]= createSequenceTc("stringvec","stringvec",_tc_string);
173   typeMap["boolvec"]= createSequenceTc("boolvec","boolvec",_tc_bool);
174   typeMap["seqdblevec"]= createSequenceTc("seqdblevec","seqdblevec",typeMap["dblevec"]);
175   typeMap["seqintvec"]= createSequenceTc("seqintvec","seqintvec",typeMap["intvec"]);
176   typeMap["seqstringvec"]= createSequenceTc("seqstringvec","seqstringvec",typeMap["stringvec"]);
177   typeMap["seqboolvec"]= createSequenceTc("seqboolvec","seqboolvec",typeMap["boolvec"]);
178   std::list<TypeCodeObjref *> ltc;
179   typeMap["pyobj"]= createInterfaceTc("python:obj:1.0","pyobj",ltc);
180   ENGINE::TypeCodeStruct *t = createStructTc("","Engines/dataref");
181   t->addMember("ref",_tc_string);
182   typeMap["dataref"]= t;
183 }
184
185 RuntimeSALOME::RuntimeSALOME(long flags, int argc, char* argv[])
186 {
187   // If all flags (apart the IsPyExt flags) are unset, force them to true
188   if ((flags - flags & RuntimeSALOME::IsPyExt) == 0)
189     flags += RuntimeSALOME::UseCorba + RuntimeSALOME::UsePython
190           +  RuntimeSALOME::UseCpp + RuntimeSALOME::UseXml;
191
192   // Salome Nodes implies Corba Nodes
193   if (flags & RuntimeSALOME::UseSalome)
194     flags |= RuntimeSALOME::UseCorba;
195
196   // Corba Nodes implies Python Nodes
197   if (flags & RuntimeSALOME::UseCorba)
198     flags |= RuntimeSALOME::UsePython;
199
200   _useCorba = flags & RuntimeSALOME::UseCorba;
201   _usePython = flags & RuntimeSALOME::UsePython;
202   _useCpp = flags & RuntimeSALOME::UseCpp;
203   _useXml = flags & RuntimeSALOME::UseXml;
204
205   /* Init libxml */
206   xmlInitParser();
207
208   if (_useCpp)    _setOfImplementation.insert(CppNode::IMPL_NAME);
209   if (_usePython) _setOfImplementation.insert(PythonNode::IMPL_NAME);
210   if (_useCorba)  _setOfImplementation.insert(CORBANode::IMPL_NAME);
211   if (_useXml)    _setOfImplementation.insert(XmlNode::IMPL_NAME);
212   init(flags, argc, argv);
213 }
214
215 RuntimeSALOME::~RuntimeSALOME()
216 {
217   DEBTRACE("RuntimeSALOME::~RuntimeSALOME");
218   // destroy catalog loader prototypes
219   std::map<std::string, CatalogLoader*>::const_iterator pt;
220   for(pt=_catalogLoaderFactoryMap.begin();pt!=_catalogLoaderFactoryMap.end();pt++)
221     {
222       delete (*pt).second;
223     }
224 }
225
226 //! CORBA and Python initialization
227 /*!
228  *  \param flags contains several bits
229  *            bit0 (ispyext) true when method is called from Python
230  *                           (Python initialization must not be done!)
231  *            bit1 (UsePython) true if python nodes are needed
232  *            bit1 (UseCorba)  true if CORBA nodes are needed
233  *            bit1 (UseXml)    true if python nodes are needed
234  *            bit1 (UseCpp)    true if C++ nodes are needed
235  *            bit1 (UseSalome) true if Salome nodes are needed
236  *  \param argc number of command line arguments (used to initialize the Python interpreter)
237  *  \param argv command line arguments (used to initialize the Python interpreter)
238  *
239  */
240
241 void RuntimeSALOME::init(long flags, int argc, char* argv[])
242 {
243   bool ispyext = flags & RuntimeSALOME::IsPyExt;
244   if (_useCorba)
245     {
246       PortableServer::POA_var root_poa;
247       PortableServer::POAManager_var pman;
248       CORBA::Object_var obj;
249       int nbargs = 0; char **args = 0;
250       _orb = CORBA::ORB_init (nbargs, args);
251       obj = _orb->resolve_initial_references("RootPOA");
252       root_poa = PortableServer::POA::_narrow(obj);
253       pman = root_poa->the_POAManager();
254       pman->activate();
255
256 #ifdef REFCNT
257       DEBTRACE("_orb refCount: " << ((omniOrbORB*)_orb.in())->pd_refCount);
258 #endif
259       obj = _orb->resolve_initial_references("DynAnyFactory");
260       _dynFactory = DynamicAny::DynAnyFactory::_narrow(obj);
261     }
262
263   if (_usePython)
264     {
265       DEBTRACE("RuntimeSALOME::init, is python extension = " << ispyext);
266
267       // Initialize Python interpreter in embedded mode
268       if (!Py_IsInitialized())
269         {
270 #if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0
271           Py_Initialize(); 
272 #else
273           Py_InitializeEx(0); // do not install signal handlers
274 #endif
275           if (argc > 0 && argv != NULL)
276             PySys_SetArgv(argc, argv);
277           else
278             {
279               int pyArgc = 1;
280               char* pyArgv[1];
281               char defaultName[] = "SALOME_YACS_RUNTIME";
282               pyArgv[0] = defaultName;
283               PySys_SetArgv(pyArgc, pyArgv);
284             }
285           PyEval_InitThreads(); /* Create (and acquire) the interpreter lock (for threads)*/
286           PyEval_SaveThread(); /* Release the thread state */
287           //here we do not have the Global Interpreter Lock
288         }
289
290       PyObject *mainmod,*pyapi,*res ;
291       PyObject *globals;
292       PyGILState_STATE gstate;
293       gstate = PyGILState_Ensure(); // acquire the Global Interpreter Lock
294     
295       mainmod = PyImport_AddModule("__main__");
296       globals = PyModule_GetDict(mainmod);
297       /* globals is a borrowed reference */
298   
299       if (PyDict_GetItemString(globals, "__builtins__") == NULL) 
300         {
301           PyObject *bimod = PyImport_ImportModule("__builtin__");
302           if (bimod == NULL || PyDict_SetItemString(globals, "__builtins__", bimod) != 0)
303             Py_FatalError("can't add __builtins__ to __main__");
304           Py_DECREF(bimod);
305         }
306
307       _bltins = PyEval_GetBuiltins();  /* borrowed ref */
308
309       if (_useCorba)
310         {
311
312           //init section
313           _omnipy = PyImport_ImportModule((char*)"_omnipy");
314           if (!_omnipy)
315             {
316               PyErr_Print();
317               PyErr_SetString(PyExc_ImportError, (char*)"Cannot import _omnipy");
318               goto out;
319             }
320           pyapi = PyObject_GetAttrString(_omnipy, (char*)"API");
321           if (!pyapi)
322             {
323               goto out;
324             }
325           _api = (omniORBpyAPI*)PyCObject_AsVoidPtr(pyapi);
326           Py_DECREF(pyapi);
327
328           res=PyRun_String("\n"
329                            "from math import *\n"
330                            "import sys\n"
331                            "sys.path.insert(0,'.')\n"
332                            "from omniORB import CORBA\n"
333                            "from omniORB import any\n"
334                            "orb = CORBA.ORB_init([], CORBA.ORB_ID)\n"
335                            "#print sys.getrefcount(orb)\n"
336                            "try:\n"
337                            "  import SALOME\n"
338                            "except:\n"
339                            "  pass\n"
340                            "\n",
341                            Py_file_input,globals,globals );
342           if(res == NULL)
343             {
344               PyErr_Print();
345               goto out;
346             }
347           Py_DECREF(res);
348
349           _pyorb = PyDict_GetItemString(globals,"orb");
350           /* PyDict_GetItemString returns a borrowed reference. There is no need to decref _pyorb */
351
352           PyObject *pyany;
353           pyany = PyDict_GetItemString(globals,"any");
354           /* PyDict_GetItemString returns a borrowed reference. There is no need to decref pyany */
355
356 #ifdef REFCNT
357           DEBTRACE("_orb refCount: " << ((omniOrbORB*)_orb.in())->pd_refCount);
358 #endif
359         }
360       out:
361         PyGILState_Release(gstate); // Release the Global Interpreter Lock
362     }
363   if (_useCorba)
364     {
365       // initialize the catalogLoaderFactory map with the session one
366       _catalogLoaderFactoryMap["session"]=new SessionCataLoader;
367     }
368 }
369
370 void RuntimeSALOME::fini()
371 {
372   if (_usePython)
373     {
374       PyGILState_STATE gstate = PyGILState_Ensure();
375 #ifdef REFCNT
376       DEBTRACE("_orb refCount: " << ((omniOrbORB*)_orb.in())->pd_refCount);
377 #endif
378       PyObject *mainmod, *globals;
379       mainmod = PyImport_AddModule("__main__");
380       globals = PyModule_GetDict(mainmod);
381       if (_useCorba)
382         {
383           PyObject* res;
384           res=PyRun_String("orb.destroy()\n"
385                            "\n",
386                            Py_file_input,globals,globals );
387           if(res == NULL)
388             PyErr_Print();
389           else
390             Py_DECREF(res);
391         }
392       std::map<std::string,Node*>& nodeMap=_builtinCatalog->_nodeMap;
393       delete nodeMap["PyFunction"];
394       delete nodeMap["PyScript"];
395       delete nodeMap["SalomePythonNode"];
396       nodeMap.erase("PyFunction");
397       nodeMap.erase("PyScript");
398       nodeMap.erase("SalomePythonNode");
399
400       Py_Finalize();
401 #ifdef REFCNT
402       DEBTRACE("_orb refCount: " << ((omniOrbORB*)_orb.in())->pd_refCount);
403 #endif
404     }
405   else
406     {
407       if (_useCorba)
408         {
409 #ifdef REFCNT
410           DEBTRACE("_orb refCount: " << ((omniOrbORB*)_orb.in())->pd_refCount);
411 #endif
412           _orb->destroy();
413         }
414     }
415 }
416
417 std::string RuntimeSALOME::getVersion() const
418 {
419 #ifdef YACS_DEVELOPMENT
420   return CORBA::string_dup(YACS_VERSION_STR"dev");
421 #else
422   return CORBA::string_dup(YACS_VERSION_STR);
423 #endif
424 }
425
426 Proc* RuntimeSALOME::createProc(const std::string& name)
427 {
428   return new SalomeProc(name);
429 }
430
431 TypeCode * RuntimeSALOME::createInterfaceTc(const std::string& id, const std::string& name,
432                                             std::list<TypeCodeObjref *> ltc)
433 {
434   std::string myName;
435   if(id == "") myName = "IDL:" + name + ":1.0";
436   else myName = id;
437   return TypeCode::interfaceTc(myName.c_str(),name.c_str(),ltc);
438 }
439
440 TypeCode * RuntimeSALOME::createSequenceTc(const std::string& id,
441                                            const std::string& name,
442                                            TypeCode *content)
443 {
444   return TypeCode::sequenceTc(id.c_str(),name.c_str(),content);
445 };
446
447 TypeCodeStruct * RuntimeSALOME::createStructTc(const std::string& id, const std::string& name)
448 {
449   std::string myName;
450   if(id == "") myName = "IDL:" + name + ":1.0";
451   else myName = id;
452   return (TypeCodeStruct *)TypeCode::structTc(myName.c_str(),name.c_str());
453 }
454
455 Bloc* RuntimeSALOME::createBloc(const std::string& name)
456 {
457   return new Bloc(name);
458 }
459
460 WhileLoop* RuntimeSALOME::createWhileLoop(const std::string& name)
461 {
462   return new WhileLoop(name);
463 }
464
465 ForLoop* RuntimeSALOME::createForLoop(const std::string& name)
466 {
467   return new ForLoop(name);
468 }
469
470 OptimizerLoop* RuntimeSALOME::createOptimizerLoop(const std::string& name,const std::string& algLib,const std::string& factoryName,
471                                                   bool algInitOnFile, const std::string& kind, Proc * procForTypes)
472 {
473   OptimizerLoop * ol = (kind == "base") ? new OptimizerLoop(name,algLib,factoryName,algInitOnFile, true, procForTypes) :
474                                           new SalomeOptimizerLoop(name,algLib,factoryName,algInitOnFile, true, procForTypes);
475   ol->edGetNbOfBranchesPort()->edInit(1);
476   return ol;
477 }
478
479 DataNode* RuntimeSALOME::createInDataNode(const std::string& kind,const std::string& name)
480 {
481   DataNode* node;
482   if(kind == "" )
483     {
484       node = new PresetNode(name);
485       return node;
486     }
487   else if(kind == "study" )
488     {
489       return new StudyInNode(name);
490     }
491   std::string msg="DataNode kind ("+kind+") unknown";
492   throw Exception(msg);
493 }
494
495 DataNode* RuntimeSALOME::createOutDataNode(const std::string& kind,const std::string& name)
496 {
497   if(kind == "" )
498     {
499       return new OutNode(name);
500     }
501   else if(kind == "study" )
502     {
503       return new StudyOutNode(name);
504     }
505
506   std::string msg="OutDataNode kind ("+kind+") unknown";
507   throw Exception(msg);
508 }
509
510 InlineFuncNode* RuntimeSALOME::createFuncNode(const std::string& kind,const std::string& name)
511 {
512   InlineFuncNode* node;
513   if(kind == "" || kind == SalomeNode::KIND || kind == PythonNode::KIND)
514     {
515       node = new PyFuncNode(name);
516       return node;
517     }
518   if(kind == DistributedPythonNode::KIND)
519     return new DistributedPythonNode(name);
520   std::string msg="FuncNode kind ("+kind+") unknown";
521   throw Exception(msg);
522 }
523
524 InlineNode* RuntimeSALOME::createScriptNode(const std::string& kind,const std::string& name)
525 {
526   InlineNode* node;
527   if(kind == "" || kind == SalomeNode::KIND || kind == PythonNode::KIND)
528     {
529       node = new PythonNode(name);
530       return node;
531     }
532   std::string msg="ScriptNode kind ("+kind+") unknown";
533   throw Exception(msg);
534 }
535
536 ServiceNode* RuntimeSALOME::createRefNode(const std::string& kind,const std::string& name)
537 {
538   ServiceNode* node;
539   if(kind == "" || kind == SalomeNode::KIND || kind == CORBANode::KIND)
540     {
541       node = new CORBANode(name);
542       return node;
543     }
544   else if(kind == XmlNode::KIND)
545     {
546       node = new XmlNode(name);
547       return node;
548     }
549   std::string msg="RefNode kind ("+kind+") unknown";
550   throw Exception(msg);
551 }
552
553 ServiceNode* RuntimeSALOME::createCompoNode(const std::string& kind,const std::string& name)
554 {
555   ServiceNode* node;
556   if(kind == "" || kind == SalomeNode::KIND )
557     {
558       node=new SalomeNode(name);
559       return node;
560     }
561   else if (kind == CppNode::KIND) 
562     {
563       node = new CppNode(name);
564       return node;
565     }
566   std::string msg="CompoNode kind ("+kind+") unknown";
567   throw Exception(msg);
568 }
569
570 ServiceInlineNode *RuntimeSALOME::createSInlineNode(const std::string& kind, const std::string& name)
571 {
572   if(kind == "" || kind == SalomeNode::KIND )
573     return new SalomePythonNode(name);
574   std::string msg="CompoNode kind ("+kind+") unknown";
575   throw Exception(msg);
576 }
577
578 ComponentInstance* RuntimeSALOME::createComponentInstance(const std::string& name,
579                                                           const std::string& kind)
580 {
581   ComponentInstance* compo;
582   if(kind == "" || kind == SalomeComponent::KIND) 
583     return new SalomeComponent(name);
584   else if(kind == CORBAComponent::KIND)
585     return new CORBAComponent(name);
586   else if(kind == SalomePythonComponent::KIND)
587     return new SalomePythonComponent(name);
588   else if (kind == CppComponent::KIND)
589     return new CppComponent(name);
590   std::string msg="Component Instance kind ("+kind+") unknown";
591   throw Exception(msg);
592 }
593
594 Container *RuntimeSALOME::createContainer(const std::string& kind)
595 {
596   if(kind == "" || kind == SalomeComponent::KIND)
597     return new SalomeContainer;
598   else if (kind == CppComponent::KIND)
599     return new CppContainer;
600   std::string msg="Container kind ("+kind+") unknown";
601   throw Exception(msg);
602 }
603
604 InputPort * RuntimeSALOME::createInputPort(const std::string& name,
605                                            const std::string& impl,
606                                            Node * node,
607                                            TypeCode * type)
608 {
609   if(impl == CppNode::IMPL_NAME)
610     {
611       return new InputCppPort(name, node, type);
612     }
613   else if(impl == PythonNode::IMPL_NAME)
614     {
615       return new InputPyPort(name, node, type);
616     }
617   else if(impl == CORBANode::IMPL_NAME)
618     {
619       return new InputCorbaPort(name, node, type);
620     }
621   else if(impl == XmlNode::IMPL_NAME)
622     {
623       return new InputXmlPort(name, node, type);
624     }
625   else
626     {
627       stringstream msg;
628       msg << "Cannot create " << impl << " InputPort" ;
629       msg << " ("__FILE__ << ":" << __LINE__ << ")";
630       throw Exception(msg.str());
631     }
632 }
633
634 OutputPort * RuntimeSALOME::createOutputPort(const std::string& name,
635                                              const std::string& impl,
636                                              Node * node,
637                                              TypeCode * type)
638 {
639   if(impl == CppNode::IMPL_NAME)
640     {
641       return new OutputCppPort(name, node, type);
642     }
643   else if(impl == PythonNode::IMPL_NAME)
644     {
645       return new OutputPyPort(name, node, type);
646     }
647   else if(impl == CORBANode::IMPL_NAME)
648     {
649       return new OutputCorbaPort(name, node, type);
650     }
651   else if(impl == XmlNode::IMPL_NAME)
652     {
653       return new OutputXmlPort(name, node, type);
654     }
655   else
656     {
657       stringstream msg;
658       msg << "Cannot create " << impl << " OutputPort" ;
659       msg << " ("__FILE__ << ":" << __LINE__ << ")";
660       throw Exception(msg.str());
661     }
662 }
663
664 InputDataStreamPort* RuntimeSALOME::createInputDataStreamPort(const std::string& name,
665                                                               Node *node,TypeCode *type)
666 {
667   DEBTRACE("createInputDataStreamPort: " << name << " " << type->shortName());
668   if(type->kind() == Objref && std::string(type->shortName(),7) == "CALCIUM")
669     {
670       return new InputCalStreamPort(name,node,type);
671     }
672   else
673     {
674       return new InputDataStreamPort(name,node,type);
675     }
676 }
677
678 OutputDataStreamPort* RuntimeSALOME::createOutputDataStreamPort(const std::string& name,
679                                                                 Node *node,TypeCode *type)
680 {
681   DEBTRACE("createOutputDataStreamPort: " << name << " " << type->shortName());
682   if(type->kind() == Objref && std::string(type->shortName(),7) == "CALCIUM")
683     {
684       return new OutputCalStreamPort(name,node,type);
685     }
686   else
687     {
688       return new OutputDataStreamPort(name,node,type);
689     }
690 }
691
692 //! Main adapter function : adapt an InputPort to be able to connect it to an OutputPort with a possible different implementation 
693 /*!
694  *  \param source : InputPort to be adapted
695  *  \param impl : new implementation (C++, python, CORBA, XML, Neutral)
696  *  \param type : data type provided by the InputPort
697  *  \param init : indicates if the adapted InputPort will be used for initialization (value true) or not (value false)
698  * 
699  * \return : adapted InputPort
700  */
701 InputPort* RuntimeSALOME::adapt(InputPort* source,
702                                 const std::string& impl,
703                                 TypeCode * type,bool init) throw (ConversionException)
704 {
705   string imp_source=source->getNode()->getImplementation();
706   if(imp_source == PythonNode::IMPL_NAME)
707     {
708       return adapt((InputPyPort*)source,impl,type,init);
709     }
710   else if(imp_source == CppNode::IMPL_NAME)
711     {
712       return adapt((InputCppPort*)source,impl,type,init);
713     }
714   else if(imp_source == CORBANode::IMPL_NAME)
715     {
716       return adapt((InputCorbaPort*)source,impl,type,init);
717     }
718   else if(imp_source == XmlNode::IMPL_NAME)
719     {
720       return adapt((InputXmlPort*)source,impl,type,init);
721     }
722   else if(imp_source == Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
723     {
724       return adaptNeutral(source,impl,type,init);
725     }
726   else
727     {
728       stringstream msg;
729       msg << "Cannot adapt " << imp_source << " InputPort to " << impl;
730       msg << " ("__FILE__ << ":" << __LINE__ << ")";
731       throw ConversionException(msg.str());
732     }
733 }
734
735 //! Adapter function for InPropertyPort
736 /*!
737  *  \param source : InPropertyPort to be adapted
738  *  \param impl : new implementation (C++, python, CORBA, XML, Neutral)
739  *  \param type : data type provided by the InPropertyPort
740  *  \param init : indicates if the adapted InPropertyPort will be used for initialization (value true) or not (value false)
741  * 
742  * \return : adapted InputPort
743  */
744 InputPort* RuntimeSALOME::adapt(InPropertyPort* source,
745                                 const std::string& impl,
746                                 TypeCode * type,bool init) throw (ConversionException)
747 {
748   return adaptNeutral((InputPort *)source,impl,type,init);
749 }
750
751 //! Adapt a Neutral input port to a Corba output port
752 /*!
753  *   \param inport : Neutral input port to adapt to Corba type type
754  *   \param type : output port type
755  *   \return an adaptated input port of type InputCorbaPort
756  */
757 InputPort* RuntimeSALOME::adaptNeutralToCorba(InputPort* inport,
758                       TypeCode * type) throw (ConversionException)
759 {
760   // BEWARE : using the generic check
761   if(inport->edGetType()->isAdaptable(type))
762     {
763       //the output data is convertible to inport type
764       return new CorbaNeutral(inport);
765     }
766   //non convertible type
767   stringstream msg;
768   msg << "Cannot connect Corba output port with type: " << type->id() ;
769   msg << " to Neutral input port " << inport->getName() << " with type: " << inport->edGetType()->id();
770 #ifdef _DEVDEBUG_
771   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
772 #endif
773   throw ConversionException(msg.str());
774 }
775
776 //! Adapt a Neutral input port to a Python output port
777 /*!
778  *   \param inport : input port to adapt to Python type type
779  *   \param type : output port type
780  *   \return an adaptated input port of type InputPyPort
781  */
782 InputPort* RuntimeSALOME::adaptNeutralToPython(InputPort* inport,
783                       TypeCode * type) throw (ConversionException)
784 {
785   // BEWARE : using the generic check
786   if(inport->edGetType()->isAdaptable(type))
787     {
788       //convertible type
789       return new PyNeutral(inport);
790     }
791   //non convertible type
792   stringstream msg;
793   msg << "Cannot connect Python output port with type: " << type->id() ;
794   msg << " to Neutral input port " << inport->getName() << " with type: " << inport->edGetType()->id();
795 #ifdef _DEVDEBUG_
796   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
797 #endif
798   throw ConversionException(msg.str());
799 }
800
801 //! Adapt a Neutral input port to a Xml output port 
802 /*!
803  *   \param inport : input port to adapt to Xml type type
804  *   \param type : output port type
805  *   \return an input port of type InputXmlPort
806  */
807 InputPort* RuntimeSALOME::adaptNeutralToXml(InputPort* inport,
808                       TypeCode * type) throw (ConversionException)
809 {
810   // BEWARE : using the generic check
811   if(inport->edGetType()->isAdaptable(type))
812     {
813       //convertible type
814       return new XmlNeutral(inport);
815     }
816   //non convertible type
817   stringstream msg;
818   msg << "Cannot connect Xml output port with type: " << type->id() ;
819   msg << " to Neutral input port " << inport->getName() << " with type: " << inport->edGetType()->id();
820 #ifdef _DEVDEBUG_
821   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
822 #endif
823   throw ConversionException(msg.str());
824 }
825
826 //! Adapt a Neutral input port to a C++ output port 
827 /*!
828  *   \param inport : input port to adapt to C++ type type
829  *   \param type : output port type
830  *   \return an input port of type InputCppPort
831  */
832 InputPort* RuntimeSALOME::adaptNeutralToCpp(InputPort* inport,
833                       TypeCode * type) throw (ConversionException)
834 {
835   DEBTRACE("RuntimeSALOME::adaptNeutralToCpp(InputPort* inport" );
836   if(isAdaptableNeutralCpp(type,inport->edGetType()))
837     {
838       //convertible type
839       return new CppNeutral(inport);
840     }
841   //non convertible type
842   stringstream msg;
843   msg << "Cannot connect Cpp output port with type: " << type->id() ;
844   msg << " to Neutral input port " << inport->getName() << " with type: " << inport->edGetType()->id();
845 #ifdef _DEVDEBUG_
846   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
847 #endif
848   throw ConversionException(msg.str());
849 }
850
851 //! Adapt a Neutral input port to connect it to an output port with a given implementation
852 /*!
853  *   \param source : Neutral input port to adapt to implementation impl and type type
854  *   \param impl : output port implementation (C++, Python, Corba, Xml or Neutral)
855  *   \param type : output port supported type
856  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
857  *   \return       the adaptated port
858  */
859 InputPort* RuntimeSALOME::adaptNeutral(InputPort* source,
860                                        const std::string& impl,
861                                        TypeCode * type,bool init) throw (ConversionException)
862 {
863   if(impl == CppNode::IMPL_NAME)
864     {
865       return adaptNeutralToCpp(source,type);
866     }
867   else if(impl == PythonNode::IMPL_NAME)
868     {
869       return adaptNeutralToPython(source,type);
870     }
871   else if(impl == CORBANode::IMPL_NAME)
872     {
873       return adaptNeutralToCorba(source,type);
874     }
875   else if(impl == XmlNode::IMPL_NAME )
876     {
877       return adaptNeutralToXml(source,type);
878     }
879   else if(impl == Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
880     {
881       if(init)
882         return new NeutralInit(source);
883       else
884         return new ProxyPort(source);
885     }
886   stringstream msg;
887   msg << "Cannot connect InputPort : unknown implementation " << impl;
888   msg << " (" <<__FILE__ << ":" <<__LINE__ << ")";
889   throw ConversionException(msg.str());
890 }
891
892 //! Adapt a XML input port to connect it to a CORBA output port 
893 /*!
894  *   \param inport : input port to adapt to CORBA type type
895  *   \param type : type supported by output port
896  *   \return an adaptator port of type InputCorbaPort 
897  */
898
899 InputPort* RuntimeSALOME::adaptXmlToCorba(InputXmlPort* inport,
900                                           TypeCode * type) throw (ConversionException)
901 {
902   if(isAdaptableXmlCorba(type,inport->edGetType()))
903     {
904       //output type is convertible to input type
905       return new CorbaXml(inport);
906     }
907   //output type is not convertible
908   stringstream msg;
909   msg << "Cannot connect Corba output port with type: " << type->id() ;
910   msg << " to Xml input port " << inport->getName() << " with type: " << inport->edGetType()->id();
911 #ifdef _DEVDEBUG_
912   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
913 #endif
914   throw ConversionException(msg.str());
915 }
916
917 //! Adapt a XML input port to a Python output port
918 /*!
919  *   \param inport : input port to adapt to Python type type
920  *   \param type : output port type
921  *   \return an adaptated input port of type InputPyPort
922  */
923 InputPort* RuntimeSALOME::adaptXmlToPython(InputXmlPort* inport,
924                       TypeCode * type) throw (ConversionException)
925 {
926   if(inport->edGetType()->isAdaptable(type))
927     {
928       //the output data is convertible to inport type
929       return new PyXml(inport);
930     }
931   //non convertible type
932   stringstream msg;
933   msg << "Cannot connect Python output port with type: " << type->id() ;
934   msg << " to Xml input port " << inport->getName() << " with type: " << inport->edGetType()->id();
935 #ifdef _DEVDEBUG_
936   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
937 #endif
938   throw ConversionException(msg.str());
939 }
940
941 //! Adapt a XML input port to a C++ output port
942 /*!
943  *   \param inport : input port to adapt to C++ type type
944  *   \param type : output port type
945  *   \return an adaptated input port of type InputPyPort
946  */
947 InputPort* RuntimeSALOME::adaptXmlToCpp(InputXmlPort* inport,
948                       TypeCode * type) throw (ConversionException)
949 {
950   DEBTRACE("RuntimeSALOME::adaptXmlToCpp(InputPort* inport" );
951   DEBTRACE(type->kind() << "   " << inport->edGetType()->kind() );
952   if(type->isAdaptable(inport->edGetType()))
953     {
954       //the output data is convertible to inport type
955       return new CppXml(inport);
956     }
957   //non convertible type
958   stringstream msg;
959   msg << "Cannot connect Cpp output port with type: " << type->id() ;
960   msg << " to Xml input port " << inport->getName() << " with type: " << inport->edGetType()->id();
961 #ifdef _DEVDEBUG_
962   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
963 #endif
964   throw ConversionException(msg.str());
965 }
966
967 //! Adapt a XML input port to a Neutral output port
968 /*!
969  *   \param inport : input port to adapt to Neutral type type
970  *   \param type : output port type
971  *   \return an adaptated input port of type Neutralxxxx
972  */
973 InputPort* RuntimeSALOME::adaptXmlToNeutral(InputXmlPort* inport,
974                       TypeCode * type) throw (ConversionException)
975 {
976   if(inport->edGetType()->isAdaptable(type))
977     {
978       //the output data is convertible to inport type
979       return new NeutralXml(inport);
980     }
981   //non convertible type
982   stringstream msg;
983   msg << "Cannot connect Xml InputPort to OutputNeutralPort : " ;
984   msg << "(" <<__FILE__ << ":" <<__LINE__<< ")";
985   throw ConversionException(msg.str());
986 }
987
988 //! Adapt a XML input port to a Xml output port
989 /*!
990  *   \param inport : input port to adapt to Xml type type
991  *   \param type : output port type
992  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
993  *   \return an adaptated input port of type Xmlxxxx
994  */
995 InputPort* RuntimeSALOME::adaptXmlToXml(InputXmlPort* inport,
996                       TypeCode * type,bool init) throw (ConversionException)
997 {
998   if(init)
999     return new ProxyPort(inport);
1000
1001   if(inport->edGetType()->isAdaptable(type))
1002     return new ProxyPort(inport);
1003
1004   stringstream msg;
1005   msg << "Cannot connect Xml output port with type: " << type->id() ;
1006   msg << " to Xml input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1007 #ifdef _DEVDEBUG_
1008   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1009 #endif
1010   throw ConversionException(msg.str());
1011 }
1012
1013 //! Adapt an Xml input port to an output port which implementation is given by impl
1014 /*!
1015  *   \param source : input port to adapt to implementation impl and type type
1016  *   \param impl : output port implementation (C++, Python or Corba)
1017  *   \param type : output port supported type
1018  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
1019  *   \return       the adaptated port
1020  */
1021
1022 InputPort* RuntimeSALOME::adapt(InputXmlPort* source,
1023                                 const std::string& impl,
1024                                 TypeCode * type,bool init) throw (ConversionException)
1025 {
1026   if(impl == CORBANode::IMPL_NAME)
1027     {
1028       return adaptXmlToCorba(source,type);
1029     }
1030   else if(impl == PythonNode::IMPL_NAME)
1031     {
1032       return adaptXmlToPython(source,type);
1033     }
1034   else if(impl == CppNode::IMPL_NAME)
1035     {
1036       return adaptXmlToCpp(source,type);
1037     }
1038   else if(impl == XmlNode::IMPL_NAME )
1039     {
1040       return adaptXmlToXml(source,type,init);
1041     }
1042   else if(impl == Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
1043     {
1044       return adaptXmlToNeutral(source,type);
1045     }
1046   else
1047     {
1048       stringstream msg;
1049       msg << "Cannot connect InputXmlPort to " << impl << " implementation";
1050       msg << " ("__FILE__ << ":" << __LINE__ << ")";
1051       throw ConversionException(msg.str());
1052     }
1053 }
1054
1055
1056 //! Adapt a CORBA input port to a CORBA output port 
1057 /*!
1058  *   \param inport : input port to adapt to CORBA outport data type
1059  *   \param type : outport data type 
1060  *   \return an adaptator port of type InputCORBAPort 
1061  */
1062 InputPort* RuntimeSALOME::adaptCorbaToCorba(InputCorbaPort* inport,
1063                                             TypeCode * type) throw (ConversionException)
1064 {
1065   if(type->isA(inport->edGetType()))
1066     {
1067       //types are compatible : no conversion 
1068       //outport data type is more specific than inport required type
1069       //so the inport can be used safely 
1070       return new ProxyPort(inport);
1071     }
1072   else if(isAdaptableCorbaCorba(type,inport->edGetType()))
1073     {
1074       //ouport data can be converted to inport data type
1075       return new CorbaCorba(inport);
1076     }
1077   //outport data can not be converted
1078   stringstream msg;
1079   msg << "Cannot connect Corba output port with type: " << type->id() ;
1080   msg << " to CORBA input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1081 #ifdef _DEVDEBUG_
1082   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1083 #endif
1084   throw ConversionException(msg.str());
1085 }
1086
1087 //! Adapt a CORBA input port to a Python output port 
1088 /*!
1089  *   \param inport : input port to adapt to Python type type
1090  *   \param type : outport data type 
1091  *   \return an adaptator port of type InputPyPort 
1092  */
1093
1094 InputPort* RuntimeSALOME::adaptCorbaToPython(InputCorbaPort* inport,
1095                                              TypeCode * type) throw (ConversionException)
1096 {
1097   if(inport->edGetType()->kind() == Double)
1098     {
1099       if(isAdaptableCorbaPyObject(type,inport->edGetType()))return new PyCorbaDouble(inport);
1100     }
1101   else if(inport->edGetType()->kind() == Int)
1102     {
1103       if(isAdaptableCorbaPyObject(type,inport->edGetType()))return new PyCorbaInt(inport);
1104     }
1105   else if(inport->edGetType()->kind() == String)
1106     {
1107       if(isAdaptableCorbaPyObject(type,inport->edGetType()))return new PyCorbaString(inport);
1108     }
1109   else if(inport->edGetType()->kind() == Bool)
1110     {
1111       if(isAdaptableCorbaPyObject(type,inport->edGetType()))return new PyCorbaBool(inport);
1112     }
1113   else if(inport->edGetType()->kind() == Objref )
1114     {
1115       if(isAdaptableCorbaPyObject(type,inport->edGetType()))
1116         {
1117           return new PyCorbaObjref(inport);
1118         }
1119       else
1120         {
1121           stringstream msg;
1122           msg << "Cannot connect Python output port with type: " << type->id() ;
1123           msg << " to CORBA input port " << inport->getName() << " with incompatible objref type: " << inport->edGetType()->id();
1124           msg << " (" << __FILE__ << ":" <<__LINE__ << ")";
1125           throw ConversionException(msg.str());
1126         }
1127     }
1128   else if(inport->edGetType()->kind() == Sequence)
1129     {
1130       if(isAdaptableCorbaPyObject(type,inport->edGetType()))
1131         {
1132           return new PyCorbaSequence(inport);
1133         }
1134       else
1135         {
1136           stringstream msg;
1137           msg << "Cannot convert this sequence type " ;
1138           msg << __FILE__ << ":" <<__LINE__;
1139           throw ConversionException(msg.str());
1140         }
1141     }
1142   else if(inport->edGetType()->kind() == YACS::ENGINE::Struct)
1143     {
1144       if(isAdaptableCorbaPyObject(type,inport->edGetType()))
1145         {
1146           return new PyCorbaStruct(inport);
1147         }
1148       else
1149         {
1150           stringstream msg;
1151           msg << "Cannot convert this struct type " << type->id() << " to " << inport->edGetType()->id();
1152           msg << __FILE__ << ":" <<__LINE__;
1153           throw ConversionException(msg.str());
1154         }
1155     }
1156   // Adaptation not possible
1157   stringstream msg;
1158   msg << "Cannot connect Python output port with type: " << type->id() ;
1159   msg << " to CORBA input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1160 #ifdef _DEVDEBUG_
1161   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1162 #endif
1163   throw ConversionException(msg.str());
1164 }
1165
1166 //! Adapt a CORBA input port to connect it to a XML output port 
1167 /*!
1168  *   \param inport : input port to adapt to Xml type type
1169  *   \param type : type supported by output port
1170  *   \return an adaptator port of type InputXmlPort 
1171  */
1172
1173 InputPort* RuntimeSALOME::adaptCorbaToXml(InputCorbaPort* inport,
1174                                           TypeCode * type) throw (ConversionException)
1175 {
1176   // BEWARE : using the generic check
1177   if(inport->edGetType()->isAdaptable(type))
1178     {
1179       //output type is convertible to input type
1180       return new XmlCorba(inport);
1181     }
1182   //output type is not convertible
1183   stringstream msg;
1184   msg << "Cannot connect Xml output port with type: " << type->id() ;
1185   msg << " to Corba input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1186 #ifdef _DEVDEBUG_
1187   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1188 #endif
1189   throw ConversionException(msg.str());
1190 }
1191
1192 //! Adapt a CORBA input port to a C++ output port 
1193 /*!
1194  *   \param inport : input port to adapt to C++ type type
1195  *   \param type : outport data type 
1196  *   \return an adaptator port of type InputCPPPort 
1197  */
1198
1199 InputPort* RuntimeSALOME::adaptCorbaToCpp(InputCorbaPort* inport,
1200                                           TypeCode * type) throw (ConversionException)
1201 {
1202   DEBTRACE("RuntimeSALOME::adaptCorbaToCpp(InputCorbaPort* inport" );
1203   if(isAdaptableCorbaCpp(type,inport->edGetType()))
1204     {
1205       //output type is convertible to input type
1206       return new CppCorba(inport);
1207     }
1208   //output type is not convertible
1209   stringstream msg;
1210   msg << "Cannot connect Cpp output port with type: " << type->id() ;
1211   msg << " to Corba input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1212 #ifdef _DEVDEBUG_
1213   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1214 #endif
1215   throw ConversionException(msg.str());
1216 }
1217
1218 //! Adapt a CORBA input port to a neutral data 
1219 /*!
1220  *   \param inport : InputPort to adapt to Neutral type type
1221  *   \param type : outport data type 
1222  *   \return an adaptator port of type Neutralxxxx
1223  */
1224
1225 InputPort* RuntimeSALOME::adaptCorbaToNeutral(InputCorbaPort* inport,
1226                                               TypeCode * type) throw (ConversionException)
1227 {
1228   if(inport->edGetType()->kind() == Double)
1229     {
1230       if(isAdaptableCorbaNeutral(type,inport->edGetType()))return new NeutralCorbaDouble(inport);
1231     }
1232   else if(inport->edGetType()->kind() == Int)
1233     {
1234       if(isAdaptableCorbaNeutral(type,inport->edGetType()))return new NeutralCorbaInt(inport);
1235     }
1236   else if(inport->edGetType()->kind() == String)
1237     {
1238       if(isAdaptableCorbaNeutral(type,inport->edGetType())) return new NeutralCorbaString(inport);
1239     }
1240   else if(inport->edGetType()->kind() == Bool)
1241     {
1242       if(isAdaptableCorbaNeutral(type,inport->edGetType()))return new NeutralCorbaBool(inport);
1243     }
1244   else if(inport->edGetType()->kind() == Objref)
1245     {
1246       if(isAdaptableCorbaNeutral(type,inport->edGetType())) return new NeutralCorbaObjref(inport);
1247     }
1248   else if(inport->edGetType()->kind() == Sequence)
1249     {
1250       if(isAdaptableCorbaNeutral(type,inport->edGetType()))
1251         return new NeutralCorbaSequence(inport);
1252       else
1253         {
1254           stringstream msg;
1255           msg << "Cannot convert this sequence type " ;
1256           msg << __FILE__ << ":" <<__LINE__;
1257           throw ConversionException(msg.str());
1258         }
1259     }
1260   else if(inport->edGetType()->kind() == Struct)
1261     {
1262       if(isAdaptableCorbaNeutral(type,inport->edGetType())) return new NeutralCorbaStruct(inport);
1263     }
1264
1265   // Adaptation not possible
1266   stringstream msg;
1267   msg << "Cannot connect Neutral output port with type: " << type->id() ;
1268   msg << " to Corba input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1269 #ifdef _DEVDEBUG_
1270   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1271 #endif
1272   throw ConversionException(msg.str());
1273 }
1274
1275 //! Adapt a CORBA input port to an output which implementation and type are given by impl and type
1276 /*!
1277  *   \param source : input port to adapt to implementation impl and type type
1278  *   \param impl : output port implementation (C++, Python or Corba)
1279  *   \param type : outport data type 
1280  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
1281  *   \return an adaptator port which type depends on impl
1282  */
1283
1284 InputPort* RuntimeSALOME::adapt(InputCorbaPort* source,
1285                                 const std::string& impl,
1286                                 TypeCode * type,bool init) throw (ConversionException)
1287 {
1288   if(impl == CppNode::IMPL_NAME)
1289     {
1290       return adaptCorbaToCpp(source,type);
1291     }
1292   else if(impl == PythonNode::IMPL_NAME)
1293     {
1294       return adaptCorbaToPython(source,type);
1295     }
1296   else if(impl == CORBANode::IMPL_NAME)
1297     {
1298       if(init)
1299         return adaptCorbaToCorba(source,type);
1300       else
1301         return adaptCorbaToCorba(source,type);
1302     }
1303   else if(impl == XmlNode::IMPL_NAME )
1304     {
1305       return adaptCorbaToXml(source,type);
1306     }
1307   else if(impl == Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
1308     {
1309       return adaptCorbaToNeutral(source,type);
1310     }
1311   else
1312     {
1313       stringstream msg;
1314       msg << "Cannot connect InputCorbaPort : unknown implementation " ;
1315       msg << __FILE__ << ":" <<__LINE__;
1316       throw ConversionException(msg.str());
1317     }
1318 }
1319
1320 //! Adapt a Python input port to a Python output port
1321 /*!
1322  * No need to make conversion or cast. 
1323  * Only check, it's possible.
1324  *   \param inport : InputPort to adapt to Python type type
1325  *   \param type : outport data type 
1326  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
1327  *   \return an adaptator port of type InputPyPort 
1328  */
1329
1330 InputPort* RuntimeSALOME::adaptPythonToPython(InputPyPort* inport,
1331                                               TypeCode * type,bool init) throw (ConversionException)
1332 {
1333   if(init)
1334     return new PyInit(inport);
1335
1336   if(isAdaptablePyObjectPyObject(type,inport->edGetType()))
1337     {
1338       //output data is convertible to input type
1339       //With python, no need to convert. Conversion will be done automatically
1340       //by the interpreter
1341       return new ProxyPort(inport);
1342     }
1343   //output data is not convertible to input type
1344   stringstream msg;
1345   msg << "Cannot connect Python output port with type: " << type->id() ;
1346   msg << " to Python input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1347 #ifdef _DEVDEBUG_
1348   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1349 #endif
1350   throw ConversionException(msg.str());
1351 }
1352
1353 //! Adapt a Python input port to a C++ output port
1354 /*!
1355  *   \param inport : InputPort to adapt to C++ type type
1356  *   \param type : outport data type 
1357  *   \return an adaptator port of C++ type (InputCppPort)
1358  */
1359
1360 InputPort* RuntimeSALOME::adaptPythonToCpp(InputPyPort* inport,
1361                                            TypeCode * type) throw (ConversionException)
1362 {
1363   DEBTRACE("RuntimeSALOME::adaptPythonToCpp(InputPyPort* inport" );
1364   if(isAdaptablePyObjectCpp(type,inport->edGetType()))
1365     {
1366       //output type is convertible to input type
1367       return new CppPy(inport);
1368     }
1369   //output type is not convertible
1370   stringstream msg;
1371   msg << "Cannot connect Cpp output port with type: " << type->id() ;
1372   msg << " to Python input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1373 #ifdef _DEVDEBUG_
1374   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1375 #endif
1376   throw ConversionException(msg.str());
1377 }
1378
1379 //! Adapt a Python input port to a Neutral data port
1380 /*!
1381  *   \param inport : InputPort to adapt to Neutral type type
1382  *   \param type : outport data type 
1383  *   \return an adaptator port of Neutral type (Neutralxxxx)
1384  */
1385
1386 InputPort* RuntimeSALOME::adaptPythonToNeutral(InputPyPort* inport,
1387                                                TypeCode * type) throw (ConversionException)
1388 {
1389   if(inport->edGetType()->kind() == Double)
1390     {
1391       if(isAdaptablePyObjectNeutral(type,inport->edGetType()))return new NeutralPyDouble(inport);
1392     }
1393   else if(inport->edGetType()->kind() == Int)
1394     {
1395       if(isAdaptablePyObjectNeutral(type,inport->edGetType()))return new NeutralPyInt(inport);
1396     }
1397   else if(inport->edGetType()->kind() == String)
1398     {
1399       if(isAdaptablePyObjectNeutral(type,inport->edGetType()))return new NeutralPyString(inport);
1400     }
1401   else if(inport->edGetType()->kind() == Bool)
1402     {
1403       if(isAdaptablePyObjectNeutral(type,inport->edGetType()))return new NeutralPyBool(inport);
1404     }
1405   else if(inport->edGetType()->kind() == Objref)
1406     {
1407       if(isAdaptablePyObjectNeutral(type,inport->edGetType()))return new NeutralPyObjref(inport);
1408     }
1409   else if(inport->edGetType()->kind() == Sequence)
1410     {
1411       if(isAdaptablePyObjectNeutral(type,inport->edGetType()))
1412         return new NeutralPySequence(inport);
1413       else
1414         {
1415           stringstream msg;
1416           msg << "Cannot convert this sequence type " ;
1417           msg << __FILE__ << ":" <<__LINE__;
1418           throw ConversionException(msg.str());
1419         }
1420     }
1421   else if(inport->edGetType()->kind() == Struct)
1422     {
1423       if(isAdaptablePyObjectNeutral(type,inport->edGetType())) return new NeutralPyStruct(inport);
1424     }
1425
1426   // Adaptation not possible
1427   stringstream msg;
1428   msg << "Cannot connect Neutral output port with type: " << type->id() ;
1429   msg << " to Python input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1430 #ifdef _DEVDEBUG_
1431   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1432 #endif
1433   throw ConversionException(msg.str());
1434 }
1435
1436 //! Adapt a Python input port to a Corba output port
1437 /*!
1438  * Always convert the data
1439  *   \param inport : InputPort to adapt to Corba type type
1440  *   \param type : outport data type 
1441  *   \return an adaptator port of Corba type (InputCorbaPort)
1442  */
1443
1444 InputPort* RuntimeSALOME::adaptPythonToCorba(InputPyPort* inport,
1445                                              TypeCode * type) throw (ConversionException)
1446 {
1447   if(inport->edGetType()->kind() == Double)
1448     {
1449       if(isAdaptablePyObjectCorba(type,inport->edGetType()))return new CorbaPyDouble(inport);
1450     }
1451   else if(inport->edGetType()->kind() == Int)
1452     {
1453       if(isAdaptablePyObjectCorba(type,inport->edGetType()))return new CorbaPyInt(inport);
1454     }
1455   else if(inport->edGetType()->kind() == String)
1456     {
1457       if(isAdaptablePyObjectCorba(type,inport->edGetType()))return new CorbaPyString(inport);
1458     }
1459   else if(inport->edGetType()->kind() == Bool)
1460     {
1461       if(isAdaptablePyObjectCorba(type,inport->edGetType()))return new CorbaPyBool(inport);
1462     }
1463   else if(inport->edGetType()->kind() == Objref)
1464     {
1465       if(isAdaptablePyObjectCorba(type,inport->edGetType()))
1466         {
1467           return new CorbaPyObjref(inport);
1468         }
1469       else
1470         {
1471           stringstream msg;
1472           msg << "Cannot connect InputCorbaPort : incompatible objref types " << type->id() << " " << inport->edGetType()->id();
1473           msg << " " << __FILE__ << ":" <<__LINE__;
1474           throw ConversionException(msg.str());
1475         }
1476     }
1477   else if(inport->edGetType()->kind() == Sequence)
1478     {
1479       if(isAdaptablePyObjectCorba(type,inport->edGetType()))
1480         {
1481           return new CorbaPySequence(inport);
1482         }
1483       else
1484         {
1485           stringstream msg;
1486           msg << "Cannot convert this sequence type " ;
1487           msg << __FILE__ << ":" <<__LINE__;
1488           throw ConversionException(msg.str());
1489         }
1490     }
1491   else if(inport->edGetType()->kind() == YACS::ENGINE::Struct)
1492     {
1493       if(isAdaptablePyObjectCorba(type,inport->edGetType()))
1494         {
1495           return new CorbaPyStruct(inport);
1496         }
1497       else
1498         {
1499           stringstream msg;
1500           msg << "Cannot convert this struct type " << type->id() << " to " << inport->edGetType()->id();
1501           msg << " " << __FILE__ << ":" <<__LINE__;
1502           throw ConversionException(msg.str());
1503         }
1504     }
1505   // Adaptation not possible
1506   stringstream msg;
1507   msg << "Cannot connect Corba output port with type: " << type->id() ;
1508   msg << " to Python input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1509 #ifdef _DEVDEBUG_
1510   msg << " ("__FILE__ << ":" << __LINE__ << ")";
1511 #endif
1512   throw ConversionException(msg.str());
1513 }
1514
1515 //! Adapt a Python input port to a Xml output port 
1516 /*!
1517  *   \param inport : input port to adapt to Xml type type
1518  *   \param type : output port type
1519  *   \return an input port of type InputXmlPort
1520  */
1521
1522 InputPort* RuntimeSALOME::adaptPythonToXml(InputPyPort* inport,
1523                                           TypeCode * type) throw (ConversionException)
1524 {
1525   // BEWARE : using the generic check
1526   if(inport->edGetType()->isAdaptable(type))
1527     {
1528       //convertible type
1529       return new XmlPython(inport);
1530     }
1531   //non convertible type
1532   stringstream msg;
1533   msg << "Cannot connect Xml output port with type: " << type->id() ;
1534   msg << " to Python input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1535 #ifdef _DEVDEBUG_
1536   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1537 #endif
1538   throw ConversionException(msg.str());
1539 }
1540
1541 //! Adapt a Python input port to an output port with a given implementation
1542 /*!
1543  *   \param source : input port to adapt to implementation impl and type type
1544  *   \param impl : output port implementation (C++, Python or Corba)
1545  *   \param type : output port type
1546  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
1547  *   \return     adaptated input port
1548  */
1549
1550 InputPort* RuntimeSALOME::adapt(InputPyPort* source,
1551                                 const std::string& impl,
1552                                 TypeCode * type,bool init) throw (ConversionException)
1553 {
1554   if(impl == CppNode::IMPL_NAME)
1555     {
1556       return adaptPythonToCpp(source,type);
1557     }
1558   else if(impl == PythonNode::IMPL_NAME)
1559     {
1560       return adaptPythonToPython(source,type,init);
1561     }
1562   else if(impl == CORBANode::IMPL_NAME)
1563     {
1564       return adaptPythonToCorba(source,type);
1565     }
1566   else if(impl == Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
1567     {
1568       return adaptPythonToNeutral(source,type);
1569     }
1570   else if(impl == XmlNode::IMPL_NAME)
1571     {
1572       return adaptPythonToXml(source,type);
1573     }
1574   else
1575     {
1576       stringstream msg;
1577       msg << "Cannot connect InputPyPort : unknown implementation " << impl;
1578       msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1579       throw ConversionException(msg.str());
1580     }
1581 }
1582
1583
1584 //! Adapt a C++ input port to connect it to a CORBA output port
1585 /*!
1586  *   \param inport : input port to adapt to CORBA type type
1587  *   \param type : type supported by output port
1588  *   \return an adaptator port of type InputCorbaPort
1589  */
1590
1591 InputPort* RuntimeSALOME::adaptCppToCorba(InputCppPort* inport,
1592                                           TypeCode * type) throw (ConversionException)
1593 {
1594   DEBTRACE("RuntimeSALOME::adaptCppToCorba(InputCppPort* inport)");
1595   if(isAdaptableCppCorba(type,inport->edGetType()))
1596     {
1597       //output type is convertible to input type
1598       return new CorbaCpp(inport);
1599     }
1600   //output type is not convertible
1601   stringstream msg;
1602   msg << "Cannot connect Corba output port with type: " << type->id() ;
1603   msg << " to Cpp input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1604 #ifdef _DEVDEBUG_
1605   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1606 #endif
1607   throw ConversionException(msg.str());
1608 }
1609
1610 //! Adapt a C++ input port to a Python output port
1611 /*!
1612  *   \param inport : input port to adapt to Python type type
1613  *   \param type : output port type
1614  *   \return an adaptated input port of type InputPyPort
1615  */
1616 InputPort* RuntimeSALOME::adaptCppToPython(InputCppPort* inport,
1617                       TypeCode * type) throw (ConversionException)
1618 {
1619   DEBTRACE("RuntimeSALOME::adaptCppToPython(InputCppPort* inport)");
1620   if(isAdaptableCppPyObject(type,inport->edGetType()))
1621     {
1622       //output type is convertible to input type
1623       return new PyCpp(inport);
1624     }
1625   //output type is not convertible
1626   stringstream msg;
1627   msg << "Cannot connect Python output port with type: " << type->id() ;
1628   msg << " to Cpp input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1629 #ifdef _DEVDEBUG_
1630   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1631 #endif
1632   throw ConversionException(msg.str());
1633 }
1634
1635 //! Adapt a C++ input port to a C++ output port
1636 /*!
1637  *   \param inport : input port to adapt to C++ type type
1638  *   \param type : output port type
1639  *   \return an adaptated input port of type InputPyPort
1640  */
1641 InputPort* RuntimeSALOME::adaptCppToCpp(InputCppPort* inport,
1642                       TypeCode * type) throw (ConversionException)
1643 {
1644   DEBTRACE("RuntimeSALOME::adaptCppToCpp(InputPort* inport" );
1645   DEBTRACE(type->kind() << "   " << inport->edGetType()->kind() );
1646   if(type->isAdaptable(inport->edGetType()))
1647     {
1648       //the output data is convertible to inport type
1649       return new CppCpp(inport);
1650     }
1651   //non convertible type
1652   stringstream msg;
1653   msg << "Cannot connect Cpp output port with type: " << type->id() ;
1654   msg << " to Cpp input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1655 #ifdef _DEVDEBUG_
1656   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1657 #endif
1658   throw ConversionException(msg.str());
1659 }
1660
1661 //! Adapt a C++ input port to a Neutral output port
1662 /*!
1663  *   \param inport : input port to adapt to C++ type type
1664  *   \param type : output port type
1665  *   \return an adaptated input port of type InputPyPort
1666  */
1667 InputPort* RuntimeSALOME::adaptCppToNeutral(InputCppPort* inport,
1668                       TypeCode * type) throw (ConversionException)
1669 {
1670   DEBTRACE("RuntimeSALOME::adaptCppToNeutral(InputPort* inport" );
1671   DEBTRACE(type->kind() << "   " << inport->edGetType()->kind() );
1672   if(type->isAdaptable(inport->edGetType()))
1673     {
1674       //the output data is convertible to inport type
1675       return new NeutralCpp(inport);
1676     }
1677   //non convertible type
1678   stringstream msg;
1679   msg << "Cannot connect Neutral output port with type: " << type->id() ;
1680   msg << " to Cpp input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1681 #ifdef _DEVDEBUG_
1682   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1683 #endif
1684   throw ConversionException(msg.str());
1685 }
1686
1687 InputPort* RuntimeSALOME::adaptCppToXml(InputCppPort* inport,
1688                       TypeCode * type) throw (ConversionException)
1689 {
1690   DEBTRACE("RuntimeSALOME::adaptCppToXml(InputCppPort* inport" );
1691   if(isAdaptableCppXml(type,inport->edGetType()))
1692     {
1693       //convertible type
1694       return new XmlCpp(inport);
1695     }
1696   //non convertible type
1697   stringstream msg;
1698   msg << "Cannot connect Xml output port with type: " << type->id() ;
1699   msg << " to Cpp input port " << inport->getName() << " with type: " << inport->edGetType()->id();
1700 #ifdef _DEVDEBUG_
1701   msg <<  " ("<<__FILE__ << ":" << __LINE__<<")";
1702 #endif
1703    throw ConversionException(msg.str());
1704 }
1705
1706 //! Adapt a C++ input port to connect it to an output port with a given implementation
1707 /*!
1708  *   \param source : input port to adapt to implementation impl and type type
1709  *   \param impl : output port implementation (C++, Python or Corba)
1710  *   \param type : output port supported type
1711  *   \param init : if init is true the proxy port will be used in initialization of input port (needs value check)
1712  *   \return       the adaptated port
1713  */
1714
1715 InputPort* RuntimeSALOME::adapt(InputCppPort* source,
1716                                 const std::string& impl,
1717                                 TypeCode * type,bool init) throw (ConversionException)
1718 {
1719   DEBTRACE("RuntimeSALOME::adapt(InputCppPort* source)");
1720   if(impl == CORBANode::IMPL_NAME)
1721     {
1722       return adaptCppToCorba(source,type);
1723     }
1724   else if(impl == PythonNode::IMPL_NAME)
1725     {
1726       return adaptCppToPython(source,type);
1727     }
1728   else if(impl == XmlNode::IMPL_NAME)
1729     {
1730       return adaptCppToXml(source,type);
1731     }
1732   else if(impl == CppNode::IMPL_NAME)
1733     {
1734       return adaptCppToCpp(source, type);
1735     }
1736   else if(impl == Runtime::RUNTIME_ENGINE_INTERACTION_IMPL_NAME)
1737     {
1738       return adaptCppToNeutral(source, type);
1739     }
1740   else
1741     {
1742       stringstream msg;
1743       msg << "Cannot connect InputCppPort to " << impl << " implementation";
1744       msg << " ("__FILE__ << ":" << __LINE__ << ")";
1745       throw ConversionException(msg.str());
1746     }
1747 }
1748
1749 // bool RuntimeSALOME::isCompatible(const OutputPort* outputPort, 
1750 //                               const InputPort*  inputPort)
1751 // {
1752 //   bool result=true;
1753 //   return result;
1754 // }
1755
1756 CORBA::ORB_ptr RuntimeSALOME::getOrb()
1757 {
1758   return _orb;
1759 }
1760
1761 PyObject * RuntimeSALOME::getPyOrb()
1762 {
1763   return _pyorb;
1764 }
1765
1766 PyObject * RuntimeSALOME::getBuiltins()
1767 {
1768   return _bltins;
1769 }
1770
1771 DynamicAny::DynAnyFactory_ptr RuntimeSALOME::getDynFactory()
1772 {
1773   return _dynFactory;
1774 }
1775
1776 PyObject * RuntimeSALOME::get_omnipy()
1777 {
1778   return _omnipy;
1779 }
1780
1781 omniORBpyAPI* RuntimeSALOME::getApi()
1782 {
1783   return _api;
1784 }
1785
1786 void* RuntimeSALOME::convertNeutral(TypeCode * type, Any *data)
1787 {
1788   if(data)
1789     return (void *)convertNeutralPyObject(type,data);
1790   else
1791     {
1792       Py_INCREF(Py_None);
1793       return (void *)Py_None;
1794     }
1795 }
1796
1797 std::string RuntimeSALOME::convertNeutralAsString(TypeCode * type, Any *data)
1798 {
1799   PyObject* ob;
1800   if(data)
1801     {
1802       ob=convertNeutralPyObject(type,data);
1803       std::string s=convertPyObjectToString(ob);
1804
1805       // Note (Renaud Barate, 8 jan 2013): With Python 2.7, this call to Py_DECREF causes a crash
1806       // (SIGSEGV) when ob is a sequence and the call is not protected with the global interpreter
1807       // lock. I thus added the call to PyGILState_Ensure / PyGILState_Release. It worked fine in
1808       // Python 2.6 without this call. If anyone finds the real reason of this bug and another fix,
1809       // feel free to change this code.
1810       PyGILState_STATE gstate = PyGILState_Ensure();
1811       Py_DECREF(ob);
1812       PyGILState_Release(gstate);
1813       return s;
1814     }
1815   else
1816     {
1817       return "None";
1818     }
1819 }
1820
1821 std::string RuntimeSALOME::convertPyObjectToString(PyObject* ob)
1822 {
1823   return YACS::ENGINE::convertPyObjectToString(ob);
1824 }
1825
1826 PyObject* RuntimeSALOME::convertStringToPyObject(const std::string& s)
1827 {
1828   PyObject *mainmod;
1829   PyObject *globals;
1830   PyObject* ob;
1831   PyGILState_STATE gstate = PyGILState_Ensure();
1832   mainmod = PyImport_AddModule("__main__");
1833   globals = PyModule_GetDict(mainmod);
1834   PyObject* d = PyDict_New();
1835   //PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
1836   ob= PyRun_String( s.c_str(), Py_eval_input, globals, d);
1837   Py_DECREF(d);
1838   if(ob==NULL)
1839     {
1840       //exception
1841       std::string error;
1842       PyObject* new_stderr = newPyStdOut(error);
1843       PySys_SetObject((char *)"stderr", new_stderr);
1844       PyErr_Print();
1845       PySys_SetObject((char *)"stderr", PySys_GetObject((char *)"__stderr__"));
1846       Py_DECREF(new_stderr);
1847       PyGILState_Release(gstate);
1848       throw Exception(error);
1849     }
1850   PyGILState_Release(gstate);
1851   return ob;
1852 }