Salome HOME
PR: merge from branch BR_UnitTests tag mergeto_trunk_17oct05
[modules/yacs.git] / src / LifeCycleCORBA / SALOME_LifeCycleCORBA.cxx
1 //  SALOME LifeCycleCORBA : implementation of containers and engines life cycle both in Python and C++
2 //
3 //  Copyright (C) 2003  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. 
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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : SALOME_LifeCycleCORBA.cxx
25 //  Author : Paul RASCLE, EDF
26 //  Module : SALOME
27 //  $Header$
28
29 #include <iostream>
30 #include <fstream>
31 #include <sstream>
32 #include <iomanip>
33
34 #include "OpUtil.hxx"
35 #include "utilities.h"
36 #include "Launchers.hxx"
37
38 #include <ServiceUnreachable.hxx>
39
40 #include "SALOME_LifeCycleCORBA.hxx"
41 #include "SALOMETraceCollector.hxx"
42 #ifndef WNT
43 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
44 #else
45 #include "SALOME_ModuleCatalog.hh"
46 #endif
47 #include "SALOME_ContainerManager.hxx"
48 #include "SALOME_Component_i.hxx"
49 #include "SALOME_NamingService.hxx"
50 using namespace std;
51
52 IncompatibleComponent::IncompatibleComponent( void ):
53   SALOME_Exception( "IncompatibleComponent" )
54 {
55 }
56
57 IncompatibleComponent::IncompatibleComponent(const IncompatibleComponent &ex):
58   SALOME_Exception( ex ) 
59 {
60 }
61
62 //=============================================================================
63 /*! 
64  *  Constructor
65  */
66 //=============================================================================
67
68 SALOME_LifeCycleCORBA::SALOME_LifeCycleCORBA(SALOME_NamingService *ns)
69 {
70   // be sure to have an instance of traceCollector, when used via SWIG
71   // in a Python module
72   int argc = 0;
73   char *xargv = "";
74   char **argv = &xargv;
75   CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
76   //  LocalTraceCollector *myThreadTrace = SALOMETraceCollector::instance(orb);
77   if (!ns)
78     {
79       _NS = new SALOME_NamingService(orb);
80     }
81   else _NS = ns;
82   //add try catch
83   _NS->Change_Directory("/"); // mpv 250105: current directory may be not root 
84                               // (in SALOMEDS for an example)
85   // not enough: set a current directory in naming service is not thread safe
86   // if naming service instance is shared among several threads...
87   // ==> allways use absolute path and dot rely on current directory!
88
89   CORBA::Object_var obj =
90     _NS->Resolve(SALOME_ContainerManager::_ContainerManagerNameInNS);
91   ASSERT( !CORBA::is_nil(obj));
92   _ContManager=Engines::ContainerManager::_narrow(obj);
93 }
94
95 //=============================================================================
96 /*! 
97  *  Destructor
98  */
99 //=============================================================================
100
101 SALOME_LifeCycleCORBA::~SALOME_LifeCycleCORBA()
102 {
103 }
104
105 //=============================================================================
106 /*! Public - 
107  *  Find and aready existing and registered component instance.
108  *  \param params         machine parameters like type or name...
109  *  \param componentName  the name of component class
110  *  \param studyId        default = 0  : multistudy instance
111  *  \return a CORBA reference of the component instance, or _nil if not found
112  */
113 //=============================================================================
114
115 Engines::Component_ptr
116 SALOME_LifeCycleCORBA::FindComponent(const Engines::MachineParameters& params,
117                                      const char *componentName,
118                                      int studyId)
119 {
120   if (! isKnownComponentClass(componentName))
121     return Engines::Component::_nil();
122
123   Engines::MachineList_var listOfMachines =
124     _ContManager->GetFittingResources(params, componentName);
125
126   Engines::Component_var compo = _FindComponent(params,
127                                                 componentName,
128                                                 studyId,
129                                                 listOfMachines);
130
131   return compo._retn();
132 }
133
134 //=============================================================================
135 /*! Public - 
136  *  Load a component instance on a container defined by machine parameters
137  *  \param params         machine parameters like type or name...
138  *  \param componentName  the name of component class
139  *  \param studyId        default = 0  : multistudy instance
140  *  \return a CORBA reference of the component instance, or _nil if problem
141  */
142 //=============================================================================
143
144 Engines::Component_ptr
145 SALOME_LifeCycleCORBA::LoadComponent(const Engines::MachineParameters& params,
146                                      const char *componentName,
147                                      int studyId)
148 {
149   // --- Check if Component Name is known in ModuleCatalog
150
151   if (! isKnownComponentClass(componentName))
152     return Engines::Component::_nil();
153
154   Engines::MachineList_var listOfMachines =
155     _ContManager->GetFittingResources(params, componentName);
156
157   Engines::Component_var compo = _LoadComponent(params,
158                                                 componentName,
159                                                 studyId,
160                                                 listOfMachines);
161
162   return compo._retn();
163 }
164
165 //=============================================================================
166 /*! Public - 
167  *  Find and aready existing and registered component instance or load a new
168  *  component instance on a container defined by machine parameters.
169  *  \param params         machine parameters like type or name...
170  *  \param componentName  the name of component class
171  *  \param studyId        default = 0  : multistudy instance
172  *  \return a CORBA reference of the component instance, or _nil if problem
173  */
174 //=============================================================================
175
176 Engines::Component_ptr
177 SALOME_LifeCycleCORBA::
178 FindOrLoad_Component(const Engines::MachineParameters& params,
179                      const char *componentName,
180                      int studyId)
181 {
182   // --- Check if Component Name is known in ModuleCatalog
183
184   if (! isKnownComponentClass(componentName))
185     return Engines::Component::_nil();
186
187   Engines::MachineList_var listOfMachines =
188     _ContManager->GetFittingResources(params,componentName);
189
190   Engines::Component_var compo = _FindComponent(params,
191                                                 componentName,
192                                                 studyId,
193                                                 listOfMachines);
194
195   if(CORBA::is_nil(compo))
196     compo = _LoadComponent(params,
197                            componentName,
198                            studyId,
199                            listOfMachines);
200
201   return compo._retn();
202 }
203
204 //=============================================================================
205 /*! Public - 
206  *  Find and aready existing and registered component instance or load a new
207  *  component instance on a container defined by name
208  *  \param containerName  the name of container, under one of the forms
209  *           - 1 aContainer (local container)
210  *           - 2 machine/aContainer (container on hostname = machine)
211  *  \param componentName  the name of component class
212  *  \return a CORBA reference of the component instance, or _nil if problem
213  */
214 //=============================================================================
215
216 Engines::Component_ptr
217 SALOME_LifeCycleCORBA::FindOrLoad_Component(const char *containerName,
218                                             const char *componentName)
219 {
220   // --- Check if Component Name is known in ModuleCatalog
221
222   if (! isKnownComponentClass(componentName))
223     return Engines::Component::_nil();
224
225   // --- Check if containerName contains machine name (if yes: rg>0)
226
227   char *stContainer=strdup(containerName);
228   string st2Container(stContainer);
229   int rg=st2Container.find("/");
230
231   Engines::MachineParameters_var params=new Engines::MachineParameters;
232   preSet(params);
233   if (rg<0)
234     {
235       // containerName doesn't contain "/" => Local container
236       params->container_name=CORBA::string_dup(stContainer);
237       params->hostname=CORBA::string_dup(GetHostname().c_str());
238     }
239   else 
240     {
241       stContainer[rg]='\0';
242       params->container_name=CORBA::string_dup(stContainer+rg+1);
243       params->hostname=CORBA::string_dup(stContainer);
244     }
245   params->isMPI = false;
246   SCRUTE(params->container_name);
247   SCRUTE(params->hostname);
248   SCRUTE(params->OS);
249   SCRUTE(params->mem_mb);
250   SCRUTE(params->cpu_clock);
251   SCRUTE(params->nb_proc_per_node);
252   SCRUTE(params->nb_node);
253   SCRUTE(params->isMPI);
254   free(stContainer);
255   return FindOrLoad_Component(params,componentName);
256   
257 }
258
259 //=============================================================================
260 /*! Public -
261  *  Check if the component class is known in module catalog
262  *  \param componentName  the name of component class
263  *  \return true if found, false otherwise
264  */
265 //=============================================================================
266
267 bool SALOME_LifeCycleCORBA::isKnownComponentClass(const char *componentName)
268 {
269
270   try
271     {
272       CORBA::Object_var obj = _NS->Resolve("/Kernel/ModulCatalog");
273       SALOME_ModuleCatalog::ModuleCatalog_var Catalog = 
274         SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj) ;
275       ASSERT(! CORBA::is_nil(Catalog));
276       SALOME_ModuleCatalog::Acomponent_ptr compoInfo = 
277         Catalog->GetComponent(componentName);
278       if (CORBA::is_nil (compoInfo)) 
279         {
280           INFOS("Catalog Error : Component not found in the catalog");
281           return false;
282         }
283       else return true;
284     }
285   catch (ServiceUnreachable&)
286     {
287       INFOS("Caught exception: Naming Service Unreachable");
288     }
289   catch (...)
290     {
291       INFOS("Caught unknown exception.");
292     }
293   return false;
294 }
295
296 //=============================================================================
297 /*! Public -
298  *  Not so complex... useful ?
299  */
300 //=============================================================================
301
302 bool 
303 SALOME_LifeCycleCORBA::isMpiContainer(const Engines::MachineParameters& params)
304   throw(IncompatibleComponent)
305 {
306   if( params.isMPI )
307     return true;
308   else
309     return false;
310 }
311
312
313 //=============================================================================
314 /*! Public -
315  *  Pre initialisation of a given Engines::MachineParameters with default
316  *  values.
317  *  - container_name = ""  : not relevant
318  *  - hostname = ""        : not relevant
319  *  - OS = ""              : not relevant
320  *  - mem_mb = 0           : not relevant
321  *  - cpu_clock = 0        : not relevant
322  *  - nb_proc_per_node = 0 : not relevant
323  *  - nb_node = 0          : not relevant
324  *  - isMPI = false        : standard components
325  */
326 //=============================================================================
327
328 void SALOME_LifeCycleCORBA::preSet( Engines::MachineParameters& params)
329 {
330   params.container_name = "";
331   params.hostname = "";
332   params.OS = "";
333   params.mem_mb = 0;
334   params.cpu_clock = 0;
335   params.nb_proc_per_node = 0;
336   params.nb_node = 0;
337   params.isMPI = false;
338 }
339
340 //=============================================================================
341 /*! Public -
342  *  \return a number of processors not 0, only for MPI containers
343  */
344 //=============================================================================
345
346 int SALOME_LifeCycleCORBA::NbProc(const Engines::MachineParameters& params)
347 {
348   if( !isMpiContainer(params) )
349     return 0;
350   else if( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
351     return 1;
352   else if( params.nb_node == 0 )
353     return params.nb_proc_per_node;
354   else if( params.nb_proc_per_node == 0 )
355     return params.nb_node;
356   else
357     return params.nb_node * params.nb_proc_per_node;
358 }
359
360 //=============================================================================
361 /*! Protected -
362  *  Find and aready existing and registered component instance.
363  *  \param params         machine parameters like type or name...
364  *  \param componentName  the name of component class
365  *  \param studyId        default = 0  : multistudy instance
366  *  \param listOfMachines list of machine address
367  *  \return a CORBA reference of the component instance, or _nil if not found
368  * - build a list of machines on which an instance of the component is running,
369  * - find the best machine among the list
370  */
371 //=============================================================================
372
373 Engines::Component_ptr
374 SALOME_LifeCycleCORBA::
375 _FindComponent(const Engines::MachineParameters& params,
376                const char *componentName,
377                int studyId,
378                const Engines::MachineList& listOfMachines)
379 {
380   // --- build the list of machines on which the component is already running
381
382   const char *containerName = params.container_name;
383   int nbproc = NbProc(params);
384   MESSAGE("_FindComponent, required " << containerName <<
385           " " << componentName << " " << nbproc);
386
387   Engines::MachineList_var machinesOK = new Engines::MachineList;
388
389   unsigned int lghtOfmachinesOK = 0;
390   machinesOK->length(listOfMachines.length());
391
392   for(unsigned int i=0; i<listOfMachines.length(); i++)
393     {
394       const char *currentMachine=listOfMachines[i];
395       MESSAGE("_FindComponent, look at " << currentMachine);
396       CORBA::Object_var obj = _NS->ResolveComponent(currentMachine,
397                                                     containerName,
398                                                     componentName,
399                                                     nbproc);
400       if (!CORBA::is_nil(obj))
401         machinesOK[lghtOfmachinesOK++] = CORBA::string_dup(currentMachine);
402     }
403
404   // --- find the best machine among the list
405
406   if(lghtOfmachinesOK != 0)
407     {
408       machinesOK->length(lghtOfmachinesOK);
409       CORBA::String_var bestMachine = _ContManager->FindBest(machinesOK);
410       CORBA::Object_var obj = _NS->ResolveComponent(bestMachine,
411                                                     containerName,
412                                                     componentName,
413                                                     nbproc);
414       return Engines::Component::_narrow(obj);
415     }
416   else
417     return Engines::Component::_nil();
418 }
419
420 //=============================================================================
421 /*! Protected -
422  *  Load a component instance.
423  *  \param params         machine parameters like type or name...
424  *  \param componentName  the name of component class
425  *  \param studyId        default = 0  : multistudy instance
426  *  \param listOfMachines list of machine address
427  *  \return a CORBA reference of the component instance, or _nil if problem
428  *  - Finds a container in the list of machine or start one.
429  *  - Try to load the component library in the container,
430  *  - then create an instance of the component.
431  */
432 //=============================================================================
433
434 Engines::Component_ptr 
435 SALOME_LifeCycleCORBA::
436 _LoadComponent(const Engines::MachineParameters& params, 
437               const char *componentName,
438               int studyId,
439               const Engines::MachineList& listOfMachines)
440 {
441   const char *containerName = params.container_name;
442   int nbproc = NbProc(params);
443
444   MESSAGE("_LoadComponent, required " << containerName <<
445           " " << componentName << " " << nbproc);
446
447   Engines::Container_var cont =
448     _ContManager->FindOrStartContainer(params,
449                                        listOfMachines);
450   if (CORBA::is_nil(cont)) return Engines::Component::_nil();
451
452   bool isLoadable = cont->load_component_Library(componentName);
453   if (!isLoadable) return Engines::Component::_nil();
454
455   Engines::Component_var myInstance =
456     cont->create_component_instance(componentName, studyId);
457   return myInstance._retn();
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472