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