Salome HOME
updated copyright message
[modules/kernel.git] / src / ParallelContainer / SALOME_ParallelContainerProxy_i.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SALOME_ParallelContainerProxy : implementation of container and engine for Parallel Kernel
24 //  File   : SALOME_ParallelContainerProxy_i.cxx
25 //  Author : André RIBES, EDF
26 //
27 #include "SALOME_ParallelContainerProxy_i.hxx"
28
29 Container_proxy_impl_final::Container_proxy_impl_final(CORBA::ORB_ptr orb, 
30                                                        paco_fabrique_thread * fab_thread, 
31                                                        PortableServer::POA_ptr poa,
32                                                        std::string containerName,
33                                                        bool is_a_return_proxy) :
34   Engines::PACO_Container_proxy_impl(orb, fab_thread, is_a_return_proxy),
35   Engines::Container_proxy_impl(orb, fab_thread, is_a_return_proxy),
36   InterfaceManager_impl(orb, fab_thread, is_a_return_proxy)
37 {
38   _numInstance = 0;
39   _hostname = Kernel_Utils::GetHostname();
40   _containerName = _NS->BuildContainerNameForNS(containerName.c_str(), _hostname.c_str());
41   _poa = PortableServer::POA::_duplicate(poa);
42
43   _fab_thread = fab_thread;
44
45   // Add CORBA object to the poa
46   _id = _poa->activate_object(this);
47   this->_remove_ref();
48
49   // Init SALOME Naming Service
50   _NS = new SALOME_NamingService();
51   _NS->init_orb(_orb);
52
53   // Init Python container part
54   CORBA::Object_var container_node = _poa->id_to_reference(*_id);
55   CORBA::String_var sior =  _orb->object_to_string(container_node);
56   std::string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
57   myCommand += _containerName + "','";
58   myCommand += sior;
59   myCommand += "')\n";
60   Py_ACQUIRE_NEW_THREAD;
61   PyRun_SimpleString("import SALOME_Container\n");
62   PyRun_SimpleString((char*)myCommand.c_str());
63   Py_RELEASE_NEW_THREAD;
64 }
65
66 Container_proxy_impl_final:: ~Container_proxy_impl_final() {
67   if (_id)
68     delete _id;
69   if (_NS)
70     delete _NS;
71
72   // _fab_thread not deleted because fab_thread is managed
73   // by paco_fabrique_manager
74 }
75
76 void
77 Container_proxy_impl_final::Shutdown()
78 {
79   // We Start by destroying all the parallel object
80   std::list<Container_proxy_impl_final::proxy_object>::iterator itm;
81   for (itm = _par_obj_inst_list.begin(); itm != _par_obj_inst_list.end(); itm++)
82   {
83     try
84     {
85       ((*itm).proxy_corba_ref)->destroy();
86     }
87     catch(const CORBA::Exception& e)
88     {
89       // ignore this entry and continue
90     }
91     catch(...)
92     {
93       // ignore this entry and continue
94     }
95
96     // Destroy proxy object... parallel object nodes are
97     // destroyed into the Shutdown of each container nodes
98     _poa->deactivate_object(*((*itm).proxy_id));
99     if ((*itm).proxy_id)
100       delete (*itm).proxy_id;
101     if ((*itm).proxy_regist)
102       delete (*itm).proxy_regist;
103   }
104
105   // We call shutdown in each node
106   for (CORBA::ULong i = 0; i < _infos.nodes.length(); i++)
107   {
108     MESSAGE("Shutdown work node : " << i);
109     CORBA::Object_var object = _orb->string_to_object(_infos.nodes[i]);
110     Engines::Container_var node = Engines::Container::_narrow(object);
111     if (!CORBA::is_nil(node))
112     {
113       try 
114       {
115         node->Shutdown();
116         MESSAGE("Shutdown done node : " << i);
117       }
118       catch (...)
119       {
120         INFOS("Exception catch during Shutdown of node : " << i);
121       }
122     }
123     else
124     {
125       INFOS("Cannot shutdown node " << i << " ref is nil !");
126     }
127   }
128
129   INFOS("Shutdown Parallel Proxy");
130   _NS->Destroy_FullDirectory(_containerName.c_str());
131   _NS->Destroy_Name(_containerName.c_str());
132   if(!CORBA::is_nil(_orb))
133     _orb->shutdown(0);
134 }
135
136 // On intercepte cette méthode pour pouvoir ensuite
137 // déterminer si on doit créer une instance sequentielle
138 // ou parallèle d'un composant dans la méthode create_component_instance
139 CORBA::Boolean 
140 Container_proxy_impl_final::load_component_Library(const char* componentName, CORBA::String_out reason)
141 {
142   MESSAGE("Begin of load_component_Library on proxy : " << componentName);
143   reason=CORBA::string_dup("");
144
145   std::string aCompName = componentName;
146
147   CORBA::Boolean ret = true;
148   if (_libtype_map.count(aCompName) == 0)
149   {
150     _numInstanceMutex.lock(); // lock to be alone
151
152     // Default lib is seq
153     _libtype_map[aCompName] = "seq";
154
155     // --- try dlopen C++ component
156     // If is not a C++ or failed then is maybe 
157     // a seq component...
158
159     MESSAGE("Try to load C++ component");
160 #ifndef WIN32
161 #ifdef __APPLE__
162     std::string impl_name = string ("lib") + aCompName + string("Engine.dylib");
163 #else
164     std::string impl_name = string ("lib") + aCompName + string("Engine.so");
165 #endif
166 #else
167     std::string impl_name = aCompName + string("Engine.dll");
168 #endif
169     void* handle;
170 #ifndef WIN32
171     handle = dlopen( impl_name.c_str() , RTLD_LAZY | RTLD_GLOBAL ) ;
172 #else
173     handle = dlopen( impl_name.c_str() , 0 ) ;
174 #endif
175     if ( handle )
176     {
177       _library_map[impl_name] = handle;
178       MESSAGE("Library " << impl_name << " loaded");
179
180       //Test if lib could contain a parallel component
181
182       std::string paco_test_fct_signature = aCompName + std::string("_isAPACO_Component");
183       INFOS("SIG is : " << paco_test_fct_signature);
184       PACO_TEST_FUNCTION paco_test_fct = NULL;
185 #ifndef WIN32
186       paco_test_fct = (PACO_TEST_FUNCTION)dlsym(handle, paco_test_fct_signature.c_str());
187 #else
188       paco_test_fct = (PACO_TEST_FUNCTION)GetProcAddress((HINSTANCE)handle, paco_test_fct_signature.c_str());
189 #endif
190       if (paco_test_fct)
191       {
192         // PaCO Component found
193         MESSAGE("PACO LIB FOUND");
194         _libtype_map[aCompName] = "par";
195       }
196       else
197       {
198         MESSAGE("SEQ LIB FOUND");
199 #ifndef WIN32
200         MESSAGE("dlerror() result is : " << dlerror());
201 #endif
202       }
203     }
204     else
205     {
206       MESSAGE("Error in importing Cpp component : " << impl_name);
207 #ifndef WIN32
208       MESSAGE("dlerror() result is : " << dlerror());
209 #endif
210
211       MESSAGE("Try to import Python component "<<componentName);
212       Py_ACQUIRE_NEW_THREAD;
213       PyObject *mainmod = PyImport_AddModule("__main__");
214       PyObject *globals = PyModule_GetDict(mainmod);
215       PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
216       PyObject *result = PyObject_CallMethod(pyCont,
217                                              (char*)"import_component",
218                                              (char*)"s",componentName);
219       std::string ret_p= PyUnicode_AsUTF8(result);
220       Py_XDECREF(result);
221       Py_RELEASE_NEW_THREAD;
222
223       if (ret_p=="") // import possible: Python component
224       {
225         MESSAGE("import Python: " << aCompName <<" OK");
226       }
227       else
228       {
229         MESSAGE("Error in importing Python component : " << aCompName);
230         ret = false;
231       }
232     }
233     _numInstanceMutex.unlock();
234   }
235
236   // Call load_component_Library in each node
237   if (ret)
238   {
239     for (CORBA::ULong i = 0; i < _infos.nodes.length(); i++)
240     {
241       MESSAGE("Call load_component_Library work node : " << i);
242       CORBA::Object_var object = _orb->string_to_object(_infos.nodes[i]);
243       Engines::Container_var node = Engines::Container::_narrow(object);
244       if (!CORBA::is_nil(node))
245       {
246         char* reason;
247         try 
248         {
249           node->load_component_Library(componentName,reason);
250           MESSAGE("Call load_component_Library done node : " << i);
251           CORBA::string_free(reason);
252         }
253         catch (...)
254         {
255           INFOS("Exception catch during load_component_Library of node : " << i);
256           CORBA::string_free(reason);
257           ret = false;
258         }
259       }
260       else
261       {
262         INFOS("Cannot call load_component_Library node " << i << " ref is nil !");
263         ret = false;
264       }
265     }
266   }
267
268   // If ret is false -> lib is not loaded !
269   if (!ret)
270   {
271     INFOS("Cannot call load_component_Library " << aCompName);
272     _libtype_map.erase(aCompName);
273   }
274   return ret;
275 }
276
277 Engines::EngineComponent_ptr 
278 Container_proxy_impl_final::create_component_instance(const char* componentName)
279 {
280   Engines::FieldsDict_var env = new Engines::FieldsDict;
281   char* reason;
282   Engines::EngineComponent_ptr compo = create_component_instance_env(componentName, env, reason);
283   CORBA::string_free(reason);
284   return compo;
285 }
286
287 // Il y a deux cas :
288 // Composant sequentiel -> on le créer sur le noeud 0 (on pourrait faire une répartition de charge)
289 // Composant parallèle -> création du proxy ici puis appel de la création de chaque objet participant
290 // au composant parallèle
291 Engines::EngineComponent_ptr 
292 Container_proxy_impl_final::create_component_instance_env(const char* componentName,
293                                                           const Engines::FieldsDict& env, CORBA::String_out reason)
294 {
295   reason=CORBA::string_dup("");
296
297   std::string aCompName = componentName;
298   if (_libtype_map.count(aCompName) == 0)
299   {
300     // Component is not loaded !
301     INFOS("Proxy: component is not loaded ! : " << aCompName);
302     return Engines::EngineComponent::_nil();
303   }
304
305   // If it is a sequential component
306   if (_libtype_map[aCompName] == "seq")
307   {
308     _numInstanceMutex.lock(); // lock on the instance number
309     _numInstance++;
310     _numInstanceMutex.unlock();
311     Engines::PACO_Container_proxy_impl::updateInstanceNumber();
312     return Engines::Container_proxy_impl::create_component_instance(componentName);
313   }
314
315   // Parallel Component !
316   Engines::EngineComponent_var component_proxy = Engines::EngineComponent::_nil();
317
318   // On commence par créer le proxy
319 #ifndef WIN32
320 #ifdef __APPLE__
321   std::string impl_name = string ("lib") + aCompName + string("Engine.dylib");
322 #else
323   std::string impl_name = string ("lib") + aCompName + string("Engine.so");
324 #endif
325 #else
326   std::string impl_name = aCompName + string("Engine.dll");
327 #endif
328   void* handle = _library_map[impl_name];
329   std::string factory_name = aCompName + std::string("EngineProxy_factory");
330
331   MESSAGE("Creating component proxy : " << factory_name);
332   FACTORY_FUNCTION component_proxy_factory = (FACTORY_FUNCTION) dlsym(handle, factory_name.c_str());
333
334   if (!component_proxy_factory)
335   {
336     INFOS("Can't resolve symbol: " + factory_name);
337 #ifndef WIN32
338     INFOS("dlerror() result is : " << dlerror());
339 #endif
340     return Engines::EngineComponent::_nil() ;
341   }
342   try {
343     _numInstanceMutex.lock() ; // lock on the instance number
344     _numInstance++ ;
345     int numInstance = _numInstance ;
346     _numInstanceMutex.unlock() ;
347
348     char aNumI[12];
349     sprintf( aNumI , "%d" , numInstance ) ;
350     string instanceName = aCompName + "_inst_" + aNumI ;
351     string component_registerName = _containerName + "/" + instanceName;
352
353     // --- Instantiate required CORBA object
354     Container_proxy_impl_final::proxy_object * proxy = new Container_proxy_impl_final::proxy_object();
355     
356     proxy->proxy_id = (component_proxy_factory) (_orb, 
357                                                  _fab_thread,
358                                                  _poa, 
359                                                  _id,
360                                                  &(proxy->proxy_regist),
361                                                  instanceName.c_str(), 
362                                                  _parallel_object_topology.total);
363
364     // --- get reference from id
365     CORBA::Object_var obj = _poa->id_to_reference(*(proxy->proxy_id));
366     component_proxy = Engines::EngineComponent::_narrow(obj);
367     proxy->proxy_corba_ref = component_proxy;
368
369     if (!CORBA::is_nil(component_proxy))
370     {
371       _cntInstances_map[impl_name] += 1;
372       _par_obj_inst_list.push_back(*proxy);
373       delete proxy;
374
375       // --- register the engine under the name
376       //     containerName(.dir)/instanceName(.object)
377       _NS->Register(component_proxy , component_registerName.c_str()) ;
378       MESSAGE(component_registerName.c_str() << " bound" ) ;
379     }
380     else
381     {
382       INFOS("The factory returns a nil object !");
383       return Engines::EngineComponent::_nil();
384     }
385       
386   }
387   catch (...)
388   {
389     INFOS( "Exception caught in Proxy creation" );
390     return Engines::EngineComponent::_nil();
391   }
392
393   // Create on each node a work node
394   for (CORBA::ULong i = 0; i < _infos.nodes.length(); i++)
395   {
396     MESSAGE("Call create_paco_component_node_instance on work node : " << i);
397     CORBA::Object_var object = _orb->string_to_object(_infos.nodes[i]);
398     Engines::PACO_Container_var node = Engines::PACO_Container::_narrow(object);
399     if (!CORBA::is_nil(node))
400     {
401       try 
402       {
403         node->create_paco_component_node_instance(componentName, _containerName.c_str());
404         MESSAGE("Call create_paco_component_node_instance done on node : " << i);
405       }
406       catch (SALOME::SALOME_Exception & ex)
407       {
408         INFOS("SALOME_EXCEPTION : " << ex.details.text);
409         return Engines::EngineComponent::_nil();
410       }
411       catch (...)
412       {
413         INFOS("Unknown Exception catch during create_paco_component_node_instance on node : " << i);
414         return Engines::EngineComponent::_nil();
415       }
416     }
417     else
418     {
419       INFOS("Cannot call create_paco_component_node_instance on node " << i << " ref is nil !");
420       return Engines::EngineComponent::_nil();
421     }
422   }
423
424   // Start Parallel object
425   PaCO::InterfaceManager_var paco_proxy = PaCO::InterfaceManager::_narrow(component_proxy);
426   paco_proxy->start();
427
428   return component_proxy;
429 }