Salome HOME
PR: merge from BR_DATACONV_PR tag "mergeto_trunk_25oct06"
[modules/yacs.git] / src / runtime / RuntimeSALOME.cxx
1
2 #include "RuntimeSALOME.hxx"
3 #include "PythonNode.hxx"
4 #include "CORBANode.hxx"
5 #include "XMLNode.hxx"
6 #include "CppNode.hxx"
7 #include "TypeConversions.hxx"
8 #include "CORBACORBAConv.hxx"
9 #include "PythonCORBAConv.hxx"
10 #include "CORBAPythonConv.hxx"
11 #include "XMLCORBAConv.hxx"
12
13 #include <omniORB4/CORBA.h>
14 #include <iostream>
15 #include <sstream>
16 #include <cassert>
17
18 using namespace std;
19 using namespace YACS::ENGINE;
20
21
22
23 void RuntimeSALOME::setRuntime() // singleton creation (not thread safe!)
24 {
25   if (! Runtime::_singleton) Runtime::_singleton = new RuntimeSALOME();
26 }
27
28 RuntimeSALOME* YACS::ENGINE::getSALOMERuntime()
29 {
30   assert(Runtime::_singleton);
31   return dynamic_cast< RuntimeSALOME* >(Runtime::_singleton);
32 }
33
34 /**
35  *  Singleton creation, initialize converter map
36  */
37   
38 RuntimeSALOME::RuntimeSALOME()
39 {
40   _setOfImplementation.insert("Cpp");
41   _setOfImplementation.insert("Python");
42   _setOfImplementation.insert("CORBA");
43   init();
44 }
45
46
47 void RuntimeSALOME::init()
48 {
49   int nbargs = 0; char **args = 0;
50   _orb = CORBA::ORB_init (nbargs, args);
51   CORBA::Object_var obj = _orb->resolve_initial_references("DynAnyFactory");
52   _dynFactory = DynamicAny::DynAnyFactory::_narrow(obj);
53
54   PyObject *mainmod ;
55   cerr << "RuntimeSALOME::init" << endl;
56   Py_Initialize();
57
58   mainmod = PyImport_AddModule("__main__");
59   PyObject *globals;
60   globals = PyModule_GetDict(mainmod);
61
62   /* globals is a borrowed reference */
63   Py_INCREF(globals);
64   /* globals is a new reference */
65   
66   _bltins = PyEval_GetBuiltins();  /* borrowed ref */
67   
68   //init section
69   PyObject* omnipy = PyImport_ImportModule((char*)"_omnipy");
70   if (!omnipy)
71     {
72       PyErr_SetString(PyExc_ImportError, (char*)"Cannot import _omnipy");
73       return;
74     }
75   PyObject* pyapi = PyObject_GetAttrString(omnipy, (char*)"API");
76   _api = (omniORBpyAPI*)PyCObject_AsVoidPtr(pyapi);
77   Py_DECREF(pyapi);
78   PyObject *res=PyRun_String("\n"
79                              "import sys\n"
80                              "sys.path.insert(0,'.')\n"
81                              "import CORBA\n"
82                              "from omniORB import any\n"
83                              "orb = CORBA.ORB_init([], CORBA.ORB_ID)\n"
84                              "print sys.getrefcount(orb)\n"
85                              "\n",
86                              Py_file_input,globals,globals );
87   if(res == NULL)
88     {
89       PyErr_Print();
90       return;
91     }
92   Py_DECREF(res);
93   _pyorb = PyDict_GetItemString(globals,"orb");
94   cerr << "refcnt: " << _pyorb->ob_refcnt << endl;
95   PyObject_Print(_pyorb,stdout,Py_PRINT_RAW);
96   cerr << endl;
97   /* pyorb is a borrowed reference */
98   //Py_INCREF(pyorb); pas nécessaire
99
100   PyObject *pyany;
101   pyany = PyDict_GetItemString(globals,"any");
102   cerr << "pyany refcnt: " << pyany->ob_refcnt << endl;
103   /* pyany is a borrowed reference */
104 }
105
106
107 void RuntimeSALOME::fini()
108 {
109   cerr << "RuntimeSALOME::fini" << endl;
110   Py_Finalize();
111 }
112
113
114 ElementaryNode* RuntimeSALOME::createNode(string implementation,
115                                           string name) throw(Exception)
116 {
117   ElementaryNode* node = 0;
118   if (implementation == "Python")
119     node = new PythonNode(name);
120   else if (implementation == "CORBA")
121     node = new CORBANode(name);
122   else if (implementation == "XML")
123     node = new XmlNode(name);
124   else if (implementation == "Cpp")
125     node = new CppNode(name);
126   else 
127     {
128       string what ="RuntimeSALOME does not handle this implementation: " + implementation;
129       throw Exception(what);
130     }
131   return node;
132 }
133
134 InputPort * RuntimeSALOME::createInputPort(const string& name,
135                                            const string& impl,
136                                            Node * node,
137                                            TypeCode * type)
138 {
139   if(impl == "CPP")
140     {
141       throw Exception("Cannot create InputCppPort ");
142     }
143   else if(impl == "Python")
144     {
145       return new InputPyPort(name, node, type);
146     }
147   else if(impl == "CORBA")
148     {
149       return new InputCorbaPort(name, node, type);
150     }
151   else if(impl == "XML")
152     {
153       return new InputXmlPort(name, node, type);
154     }
155   else
156     {
157       stringstream msg;
158       msg << "Cannot create " << impl << " InputPort" ;
159       msg << " ("__FILE__ << ":" << __LINE__ << ")";
160       throw Exception(msg.str());
161     }
162 }
163
164 OutputPort * RuntimeSALOME::createOutputPort(const string& name,
165                                              const string& impl,
166                                              Node * node,
167                                              TypeCode * type)
168 {
169   if(impl == "CPP")
170     {
171       throw Exception("Cannot create OutputCppPort ");
172     }
173   else if(impl == "Python")
174     {
175       return new OutputPyPort(name, node, type);
176     }
177   else if(impl == "CORBA")
178     {
179       return new OutputCorbaPort(name, node, type);
180     }
181   else if(impl == "XML")
182     {
183       return new OutputXmlPort(name, node, type);
184     }
185   else
186     {
187       stringstream msg;
188       msg << "Cannot create " << impl << " OutputPort" ;
189       msg << " ("__FILE__ << ":" << __LINE__ << ")";
190       throw Exception(msg.str());
191     }
192 }
193
194 InputPort* RuntimeSALOME::adapt(const string& imp_source,
195                                 InputPort* source,
196                                 const string& impl,
197                                 TypeCode * type) throw (ConversionException)
198 {
199   cerr<<"RuntimeSALOME::adapt(InputPort* source" << endl;
200   if(imp_source == "Python")
201     {
202       return adapt((InputPyPort*)source,impl,type);
203     }
204   else if(imp_source == "CORBA")
205     {
206       return adapt((InputCorbaPort*)source,impl,type);
207     }
208   else if(imp_source == "XML")
209     {
210       return adapt((InputXmlPort*)source,impl,type);
211     }
212   else
213     {
214       stringstream msg;
215       msg << "Cannot adapt " << imp_source << " InputPort to " << impl;
216       msg << " ("__FILE__ << ":" << __LINE__ << ")";
217       throw ConversionException(msg.str());
218     }
219 }
220
221 //! Retourne un adaptateur d'un port entrant Xml pour un port sortant dont l'implémentation est donnée par impl
222 /*!
223  *   \param source : input port to adapt to implementation impl and type type
224  *   \param impl : output port implementation (C++, Python or Corba)
225  *   \param type : le type supporté par le port sortant
226  *   \return input port adapté à l'implémentation
227  */
228
229 InputPort* RuntimeSALOME::adapt(InputXmlPort* source,
230                                 const string& impl,
231                                 TypeCode * type) throw (ConversionException)
232 {
233   cerr<<"RuntimeSALOME::adapt(InputXmlPort* source" << endl;
234   if(impl == "CORBA")
235     {
236       return adaptXmlToCorba(source,type);
237     }
238   else
239     {
240       stringstream msg;
241       msg << "Cannot connect InputXmlPort to " << impl << " implementation";
242       msg << " ("__FILE__ << ":" << __LINE__ << ")";
243       throw ConversionException(msg.str());
244     }
245 }
246
247 //! Retourne un adaptateur d'un port entrant XML pour un port sortant CORBA
248 /*!
249  *   \param inport : input port to adapt to CORBA type type
250  *   \param type : le type supporté par le port sortant
251  *   \return a InputCorbaPort port
252  */
253
254 InputPort* RuntimeSALOME::adaptXmlToCorba(InputXmlPort* inport,
255                                           TypeCode * type) throw (ConversionException)
256 {
257   cerr <<"RuntimeSALOME::adaptXmlToCorba(InputXmlPort* inport" << endl;
258   if(isAdaptableXmlCorba(type,inport->type()))
259     {
260       //les types sont convertibles
261       return new CorbaXml(inport);
262     }
263   //les types sont non convertibles
264   stringstream msg;
265   msg << "Cannot connect InputXmlPort to Corba output port " ;
266   msg << type->id() << " != " << inport->type()->id();
267   msg << " ("__FILE__ << ":" << __LINE__ << ")";
268   throw ConversionException(msg.str());
269 }
270
271 //! Retourne un adaptateur d'un port entrant CORBA pour un port sortant Xml
272 /*!
273  *   \param inport : input port to adapt to Xml type type
274  *   \param type : le type supporté par le port sortant
275  *   \return an input port of Python type InputXmlPort
276  */
277
278 InputPort* RuntimeSALOME::adaptCorbaToXml(InputCorbaPort* inport,
279                                           TypeCode * type) throw (ConversionException)
280 {
281   //ATTENTION : on utilise isAdaptableCorbaPyObject (meme fonction)
282   cerr << "RuntimeSALOME::adaptCorbaToXml(InputCorbaPort* inport" << endl;
283   if(isAdaptableCorbaPyObject(type,inport->type()))
284     {
285       //les types sont convertibles
286       return new XmlCorba(inport);
287     }
288   //les types sont non convertibles
289   stringstream msg;
290   msg << "Cannot connect InputCorbaPort with OutputXmlPort : " ;
291   msg << __FILE__ << ":" <<__LINE__;
292   throw ConversionException(msg.str());
293 }
294
295
296 //! Retourne un adaptateur d'un port entrant CORBA pour un port sortant CORBA
297 /*!
298  *   \param inport : input port to adapt to CORBA type type
299  *   \param type : le type supporté par le port sortant
300  */
301
302 InputPort* RuntimeSALOME::adaptCorbaToCorba(InputCorbaPort* inport,
303                                             TypeCode * type) throw (ConversionException)
304 {
305   if(type->is_a(inport->type()))
306     {
307       //les types sont compatibles : pas de conversion
308       return inport;
309     }
310   else if(isAdaptableCorbaCorba(type,inport->type()))
311     {
312       //les types sont convertibles
313       return new CorbaCorba(inport);
314     }
315   //les types sont non convertibles
316   stringstream msg;
317   msg << "Cannot connect 2 CorbaPort with non convertible types: " ;
318   msg << type->id() << " != " << inport->type()->id();
319   throw ConversionException(msg.str());
320 }
321
322 //! Retourne un adaptateur d'un port entrant CORBA pour un port sortant Python
323 /*!
324  *   \param inport : input port to adapt to Python type type
325  *   \param type : le type supporté par le port sortant
326  *   \return an input port of Python type InputPyPort
327  */
328
329 InputPort* RuntimeSALOME::adaptCorbaToPython(InputCorbaPort* inport,
330                                              TypeCode * type) throw (ConversionException)
331 {
332   if(inport->type()->kind() == Double)
333     {
334       if(isAdaptableCorbaPyObject(type,inport->type()))return new PyCorbaDouble(inport);
335     }
336   else if(inport->type()->kind() == Int)
337     {
338       if(isAdaptableCorbaPyObject(type,inport->type()))return new PyCorbaInt(inport);
339     }
340   else if(inport->type()->kind() == String)
341     {
342       if(isAdaptableCorbaPyObject(type,inport->type()))return new PyCorbaString(inport);
343     }
344   else if(inport->type()->kind() == Objref )
345     {
346       if(isAdaptableCorbaPyObject(type,inport->type()))
347         {
348           return new PyCorbaObjref(inport);
349         }
350       else
351         {
352           stringstream msg;
353           msg << "Cannot connect InputPyPort : incompatible objref types ";
354           msg << __FILE__ << ":" <<__LINE__;
355           throw ConversionException(msg.str());
356         }
357     }
358   else if(inport->type()->kind() == Sequence)
359     {
360       if(isAdaptableCorbaPyObject(type,inport->type()))
361         {
362           return new PyCorbaSequence(inport);
363         }
364       else
365         {
366           stringstream msg;
367           msg << "Cannot convert this sequence type " ;
368           msg << __FILE__ << ":" <<__LINE__;
369           throw ConversionException(msg.str());
370         }
371     }
372   // Adaptation not found
373   stringstream msg;
374   msg << "Cannot connect InputCorbaPort to Python output " ;
375   msg << __FILE__ << ":" <<__LINE__;
376   throw ConversionException(msg.str());
377 }
378
379 //! Retourne un adaptateur d'un port entrant CORBA pour un port sortant C++
380 /*!
381  *   \param inport : input port to adapt to C++ type type
382  *   \param type : le type supporté par le port sortant
383  */
384
385 InputPort* RuntimeSALOME::adaptCorbaToCpp(InputCorbaPort* inport,
386                                           TypeCode * type) throw (ConversionException)
387 {
388   throw ConversionException("Cannot connect InputCorbaPort to C++ ");
389 }
390
391 //! Retourne un adaptateur d'un port entrant CORBA pour un port sortant dont l'implémentation est donnée par impl
392 /*!
393  *   \param source : input port to adapt to implementation impl and type type
394  *   \param impl : output port implementation (C++, Python or Corba)
395  *   \param type : le type supporté par le port sortant
396  */
397
398 InputPort* RuntimeSALOME::adapt(InputCorbaPort* source,
399                                 const string& impl,
400                                 TypeCode * type) throw (ConversionException)
401 {
402   cerr<<"RuntimeSALOME::adapt(InputPyPort* source" << endl;
403   if(impl == "CPP")
404     {
405       return adaptCorbaToCpp(source,type);
406     }
407   else if(impl == "Python")
408     {
409       return adaptCorbaToPython(source,type);
410     }
411   else if(impl == "CORBA")
412     {
413       return adaptCorbaToCorba(source,type);
414     }
415   else if(impl == "XML")
416     {
417       return adaptCorbaToXml(source,type);
418     }
419    else
420     {
421       stringstream msg;
422       msg << "Cannot connect InputCorbaPort : unknown implementation " ;
423       msg << __FILE__ << ":" <<__LINE__;
424       throw ConversionException(msg.str());
425     }
426   return source;
427 }
428
429 //! Retourne un adaptateur d'un port entrant Python pour un port sortant Python
430 /*!
431  * Dans ce cas, on ne fait pas de conversion ni de cast (int->double, par ex).
432  * On vérifie simplement que la connexion est autorisée.
433  *   \param inport : InputPort to adapt to Python type type
434  *   \param type : le TypeCode supporté par le port sortant
435  *   \return       InputPort de type Python (InputPyPort)
436  */
437
438 InputPort* RuntimeSALOME::adaptPythonToPython(InputPyPort* inport,
439                                               TypeCode * type) throw (ConversionException)
440 {
441   if(isAdaptablePyObjectPyObject(type,inport->type()))
442     {
443       //les types sont convertibles
444       //En Python, il n'est pas nécessaire de convertir. La conversion
445       //sera faite à la volée dans l'interpréteur
446       return inport;
447     }
448   //les types sont non convertibles
449   stringstream msg;
450   msg << "Cannot connect 2 Python Port with non convertible types: " ;
451   msg << type->id() << " != " << inport->type()->id();
452   throw ConversionException(msg.str());
453 }
454
455 //! Retourne un adaptateur d'un port entrant Python pour un port sortant C++
456 /*!
457  * Pas encore implémenté
458  *   \param inport : InputPort to adapt to C++ type type
459  *   \param type : le TypeCode supporté par le port sortant
460  *   \return       InputPort de type C++ (InputCppPort)
461  */
462
463 InputPort* RuntimeSALOME::adaptPythonToCpp(InputPyPort* inport,
464                                            TypeCode * type) throw (ConversionException)
465 {
466   throw ConversionException("Cannot connect InputPyPort to C++ ");
467 }
468
469 //! Retourne un adaptateur d'un port entrant Python pour un port sortant Corba
470 /*!
471  * On convertit dans tous les cas
472  *   \param inport : InputPort to adapt to Corba type type
473  *   \param type : le TypeCode supporté par le port sortant
474  *   \return       InputPort de type Corba (InputCorbaPort)
475  */
476
477 InputPort* RuntimeSALOME::adaptPythonToCorba(InputPyPort* inport,
478                                              TypeCode * type) throw (ConversionException)
479 {
480   cerr << "RuntimeSALOME::adaptPythonToCorba:" ;
481   cerr << inport->type()->kind() << ":" << type->kind()<< endl;
482
483   if(inport->type()->kind() == Double)
484     {
485       if(isAdaptablePyObjectCorba(type,inport->type()))return new CorbaPyDouble(inport);
486     }
487   else if(inport->type()->kind() == Int)
488     {
489       if(isAdaptablePyObjectCorba(type,inport->type()))return new CorbaPyInt(inport);
490     }
491   else if(inport->type()->kind() == String)
492     {
493       if(isAdaptablePyObjectCorba(type,inport->type()))return new CorbaPyString(inport);
494     }
495   else if(inport->type()->kind() == Objref)
496     {
497       if(isAdaptablePyObjectCorba(type,inport->type()))
498         {
499           return new CorbaPyObjref(inport);
500         }
501       else
502         {
503           stringstream msg;
504           msg << "Cannot connect InputCorbaPort : incompatible objref types ";
505           msg << __FILE__ << ":" <<__LINE__;
506           throw ConversionException(msg.str());
507         }
508     }
509   else if(inport->type()->kind() == Sequence)
510     {
511       if(isAdaptablePyObjectCorba(type,inport->type()))
512         {
513           return new CorbaPySequence(inport);
514         }
515       else
516         {
517           stringstream msg;
518           msg << "Cannot convert this sequence type " ;
519           msg << __FILE__ << ":" <<__LINE__;
520           throw ConversionException(msg.str());
521         }
522     }
523   // Adaptation not found
524   stringstream msg;
525   msg << "Cannot connect InputPyPort to Corba output " ;
526   msg <<  __FILE__ << ":" << __LINE__;
527   throw ConversionException(msg.str());
528 }
529
530 //! Retourne un adaptateur d'un port entrant Python pour un port sortant dont l'implémentation est donnée par impl
531 /*!
532  *   \param source : input port to adapt to implementation impl and type type
533  *   \param impl : output port implementation (C++, Python or Corba)
534  *   \param type : le type supporté par le port sortant
535  *   \return input port adapté à l'implémentation
536  */
537
538 InputPort* RuntimeSALOME::adapt(InputPyPort* source,
539                                 const string& impl,
540                                 TypeCode * type) throw (ConversionException)
541 {
542   cerr<<"RuntimeSALOME::adapt(InputPyPort* source" << endl;
543   if(impl == "CPP")
544     {
545       return adaptPythonToCpp(source,type);
546     }
547   else if(impl == "Python")
548     {
549       return adaptPythonToPython(source,type);
550     }
551   else if(impl == "CORBA")
552     {
553       return adaptPythonToCorba(source,type);
554     }
555   else
556     {
557       throw ConversionException("Cannot connect InputPyPort : unknown implementation  ");
558     }
559 }
560
561 // bool RuntimeSALOME::isCompatible(const OutputPort* outputPort, 
562 //                               const InputPort*  inputPort)
563 // {
564 //   bool result=true;
565 //   return result;
566 // }
567
568 CORBA::ORB_ptr RuntimeSALOME::getOrb()
569 {
570   return _orb;
571 }
572
573 PyObject * RuntimeSALOME::getPyOrb()
574 {
575   return _pyorb;
576 }
577
578 PyObject * RuntimeSALOME::getBuiltins()
579 {
580   return _bltins;
581 }
582
583 DynamicAny::DynAnyFactory_ptr RuntimeSALOME::getDynFactory()
584 {
585   return _dynFactory;
586 }
587
588 omniORBpyAPI* RuntimeSALOME::getApi()
589 {
590   return _api;
591 }
592