Salome HOME
Removed CASCatch
[modules/kernel.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.salome-platform.org/ or email : webmaster.salome@opencascade.com
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 <time.h>
35 #ifndef WNT
36   #include <sys/time.h>
37 #endif
38
39 #include "OpUtil.hxx"
40 #include "utilities.h"
41
42 #include <ServiceUnreachable.hxx>
43
44 #include "SALOME_LifeCycleCORBA.hxx"
45 #ifndef WNT
46 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
47 #else
48 #include "SALOME_ModuleCatalog.hh"
49 #endif
50 #include "SALOME_ContainerManager.hxx"
51 #include "SALOME_Component_i.hxx"
52 #include "SALOME_NamingService.hxx"
53
54 using namespace std;
55
56 IncompatibleComponent::IncompatibleComponent( void ):
57   SALOME_Exception( "IncompatibleComponent" )
58 {
59 }
60
61 IncompatibleComponent::IncompatibleComponent(const IncompatibleComponent &ex):
62   SALOME_Exception( ex ) 
63 {
64 }
65
66 //=============================================================================
67 /*! 
68  *  Constructor
69  */
70 //=============================================================================
71
72 SALOME_LifeCycleCORBA::SALOME_LifeCycleCORBA(SALOME_NamingService *ns)
73 {
74   // be sure to have an instance of traceCollector, when used via SWIG
75   // in a Python module
76   int argc = 0;
77   char *xargv = "";
78   char **argv = &xargv;
79   CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
80   //  LocalTraceCollector *myThreadTrace = SALOMETraceCollector::instance(orb);
81   if (!ns)
82     {
83       _NS = new SALOME_NamingService(orb);
84     }
85   else _NS = ns;
86   //add try catch
87   _NS->Change_Directory("/"); // mpv 250105: current directory may be not root 
88                               // (in SALOMEDS for an example)
89   // not enough: set a current directory in naming service is not thread safe
90   // if naming service instance is shared among several threads...
91   // ==> allways use absolute path and dot rely on current directory!
92
93   CORBA::Object_var obj =
94     _NS->Resolve(SALOME_ContainerManager::_ContainerManagerNameInNS);
95   ASSERT( !CORBA::is_nil(obj));
96   _ContManager=Engines::ContainerManager::_narrow(obj);
97
98   obj = _NS->Resolve(SALOME_ResourcesManager::_ResourcesManagerNameInNS);
99   ASSERT( !CORBA::is_nil(obj));
100   _ResManager=Engines::ResourcesManager::_narrow(obj);
101 }
102
103 //=============================================================================
104 /*! 
105  *  Destructor
106  */
107 //=============================================================================
108
109 SALOME_LifeCycleCORBA::~SALOME_LifeCycleCORBA()
110 {
111 }
112
113 //=============================================================================
114 /*! Public - 
115  *  Find and aready existing and registered component instance.
116  *  \param params         machine parameters like type or name...
117  *  \param componentName  the name of component class
118  *  \param studyId        default = 0  : multistudy instance
119  *  \return a CORBA reference of the component instance, or _nil if not found
120  */
121 //=============================================================================
122
123 Engines::Component_ptr
124 SALOME_LifeCycleCORBA::FindComponent(const Engines::MachineParameters& params,
125                                      const char *componentName,
126                                      int studyId)
127 {
128   if (! isKnownComponentClass(componentName))
129     return Engines::Component::_nil();
130
131   Engines::CompoList clist;
132   clist.length(1);
133   clist[0] = componentName;
134   Engines::MachineList_var listOfMachines =
135     _ResManager->GetFittingResources(params, clist);
136
137   Engines::Component_var compo = _FindComponent(params,
138                                                 componentName,
139                                                 studyId,
140                                                 listOfMachines);
141
142   return compo._retn();
143 }
144
145 //=============================================================================
146 /*! Public - 
147  *  Load a component instance on a container defined by machine parameters
148  *  \param params         machine parameters like type or name...
149  *  \param componentName  the name of component class
150  *  \param studyId        default = 0  : multistudy instance
151  *  \return a CORBA reference of the component instance, or _nil if problem
152  */
153 //=============================================================================
154
155 Engines::Component_ptr
156 SALOME_LifeCycleCORBA::LoadComponent(const Engines::MachineParameters& params,
157                                      const char *componentName,
158                                      int studyId)
159 {
160   // --- Check if Component Name is known in ModuleCatalog
161
162   if (! isKnownComponentClass(componentName))
163     return Engines::Component::_nil();
164
165   Engines::CompoList clist;
166   clist.length(1);
167   clist[0] = componentName;
168   Engines::MachineList_var listOfMachines =
169     _ResManager->GetFittingResources(params, clist);
170
171   Engines::Component_var compo = _LoadComponent(params,
172                                                 componentName,
173                                                 studyId,
174                                                 listOfMachines);
175
176   return compo._retn();
177 }
178
179 //=============================================================================
180 /*! Public - 
181  *  Find and aready existing and registered component instance or load a new
182  *  component instance on a container defined by machine parameters.
183  *  \param params         machine parameters like type or name...
184  *  \param componentName  the name of component class
185  *  \param studyId        default = 0  : multistudy instance
186  *  \return a CORBA reference of the component instance, or _nil if problem
187  */
188 //=============================================================================
189
190 Engines::Component_ptr
191 SALOME_LifeCycleCORBA::
192 FindOrLoad_Component(const Engines::MachineParameters& params,
193                      const char *componentName,
194                      int studyId)
195 {
196   // --- Check if Component Name is known in ModuleCatalog
197
198   if (! isKnownComponentClass(componentName))
199     return Engines::Component::_nil();
200
201   Engines::CompoList clist;
202   clist.length(1);
203   clist[0] = componentName;
204   Engines::MachineList_var listOfMachines =
205     _ResManager->GetFittingResources(params,clist);
206
207   Engines::Component_var compo = _FindComponent(params,
208                                                 componentName,
209                                                 studyId,
210                                                 listOfMachines);
211
212   if(CORBA::is_nil(compo))
213     compo = _LoadComponent(params,
214                            componentName,
215                            studyId,
216                            listOfMachines);
217
218   return compo._retn();
219 }
220
221 //=============================================================================
222 /*! Public - 
223  *  Find and aready existing and registered component instance or load a new
224  *  component instance on a container defined by name
225  *  \param containerName  the name of container, under one of the forms
226  *           - 1 aContainer (local container)
227  *           - 2 machine/aContainer (container on hostname = machine)
228  *  \param componentName  the name of component class
229  *  \return a CORBA reference of the component instance, or _nil if problem
230  */
231 //=============================================================================
232
233 Engines::Component_ptr
234 SALOME_LifeCycleCORBA::FindOrLoad_Component(const char *containerName,
235                                             const char *componentName)
236 {
237   char *valenv=getenv("SALOME_BATCH");
238   if(valenv)
239     if (strcmp(valenv,"1")==0)
240       {
241         MESSAGE("SALOME_LifeCycleCORBA::FindOrLoad_Component BATCH " << containerName << " " << componentName ) ;
242         _NS->Change_Directory("/Containers");
243         CORBA::Object_ptr obj=_NS->Resolve(containerName);
244         Engines::Container_var cont=Engines::Container::_narrow(obj);
245         bool isLoadable = cont->load_component_Library(componentName);
246         if (!isLoadable) return Engines::Component::_nil();
247         
248         Engines::Component_ptr myInstance =
249           cont->create_component_instance(componentName, 0);
250         return myInstance;
251       }
252   MESSAGE("SALOME_LifeCycleCORBA::FindOrLoad_Component INTERACTIF " << containerName << " " << componentName ) ;
253   //#if 0
254   // --- Check if Component Name is known in ModuleCatalog
255
256   if (! isKnownComponentClass(componentName))
257     return Engines::Component::_nil();
258
259   // --- Check if containerName contains machine name (if yes: rg>0)
260
261   char *stContainer=strdup(containerName);
262   string st2Container(stContainer);
263   int rg=st2Container.find("/");
264
265   Engines::MachineParameters_var params=new Engines::MachineParameters;
266   preSet(params);
267   if (rg<0)
268     {
269       // containerName doesn't contain "/" => Local container
270       params->container_name=CORBA::string_dup(stContainer);
271       params->hostname=CORBA::string_dup(GetHostname().c_str());
272     }
273   else 
274     {
275       stContainer[rg]='\0';
276       params->container_name=CORBA::string_dup(stContainer+rg+1);
277       params->hostname=CORBA::string_dup(stContainer);
278     }
279   params->isMPI = false;
280   SCRUTE(params->container_name);
281 //   SCRUTE(params->hostname);
282 //   SCRUTE(params->OS);
283 //   SCRUTE(params->mem_mb);
284 //   SCRUTE(params->cpu_clock);
285 //   SCRUTE(params->nb_proc_per_node);
286 //   SCRUTE(params->nb_node);
287 //   SCRUTE(params->isMPI);
288   free(stContainer);
289   return FindOrLoad_Component(params,componentName);
290   //#endif  
291 }
292
293 //=============================================================================
294 /*! Public -
295  *  Check if the component class is known in module catalog
296  *  \param componentName  the name of component class
297  *  \return true if found, false otherwise
298  */
299 //=============================================================================
300
301 bool SALOME_LifeCycleCORBA::isKnownComponentClass(const char *componentName)
302 {
303
304   try
305     {
306       CORBA::Object_var obj = _NS->Resolve("/Kernel/ModulCatalog");
307       SALOME_ModuleCatalog::ModuleCatalog_var Catalog = 
308         SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj) ;
309       ASSERT(! CORBA::is_nil(Catalog));
310       SALOME_ModuleCatalog::Acomponent_var compoInfo = 
311         Catalog->GetComponent(componentName);
312       if (CORBA::is_nil (compoInfo)) 
313         {
314           INFOS("Catalog Error: Component not found in the catalog" );
315           INFOS( componentName );         
316           return false;
317         }
318       else return true;
319     }
320   catch (ServiceUnreachable&)
321     {
322       INFOS("Caught exception: Naming Service Unreachable");
323     }
324   catch (...)
325     {
326       INFOS("Caught unknown exception.");
327     }
328   return false;
329 }
330
331 //=============================================================================
332 /*! Public -
333  *  Not so complex... useful ?
334  */
335 //=============================================================================
336
337 bool 
338 SALOME_LifeCycleCORBA::isMpiContainer(const Engines::MachineParameters& params)
339   throw(IncompatibleComponent)
340 {
341   if( params.isMPI )
342     return true;
343   else
344     return false;
345 }
346
347
348 //=============================================================================
349 /*! Public -
350  *  Pre initialisation of a given Engines::MachineParameters with default
351  *  values.
352  *  - container_name = ""  : not relevant
353  *  - hostname = ""        : not relevant
354  *  - OS = ""              : not relevant
355  *  - mem_mb = 0           : not relevant
356  *  - cpu_clock = 0        : not relevant
357  *  - nb_proc_per_node = 0 : not relevant
358  *  - nb_node = 0          : not relevant
359  *  - isMPI = false        : standard components
360  */
361 //=============================================================================
362
363 void SALOME_LifeCycleCORBA::preSet( Engines::MachineParameters& params)
364 {
365   params.container_name = "";
366   params.hostname = "";
367   params.OS = "";
368   params.mem_mb = 0;
369   params.cpu_clock = 0;
370   params.nb_proc_per_node = 0;
371   params.nb_node = 0;
372   params.isMPI = false;
373
374   params.parallelLib = "";
375   params.nb_component_nodes = 0;
376 }
377
378 //=============================================================================
379 /*! Public -
380  *  \return a number of processors not 0, only for MPI containers
381  */
382 //=============================================================================
383
384 int SALOME_LifeCycleCORBA::NbProc(const Engines::MachineParameters& params)
385 {
386   if( !isMpiContainer(params) )
387     return 0;
388   else if( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
389     return 1;
390   else if( params.nb_node == 0 )
391     return params.nb_proc_per_node;
392   else if( params.nb_proc_per_node == 0 )
393     return params.nb_node;
394   else
395     return params.nb_node * params.nb_proc_per_node;
396 }
397
398 //=============================================================================
399 /*! Public -
400  *  \return the container Manager
401  */
402 //=============================================================================
403
404 Engines::ContainerManager_ptr SALOME_LifeCycleCORBA::getContainerManager()
405 {
406  Engines::ContainerManager_var contManager =
407    Engines::ContainerManager::_duplicate(_ContManager);
408  return contManager._retn();
409 }
410
411 //=============================================================================
412 /*! Public -
413  *  \return the container Manager
414  */
415 //=============================================================================
416
417 Engines::ResourcesManager_ptr SALOME_LifeCycleCORBA::getResourcesManager()
418 {
419  Engines::ResourcesManager_var resManager =
420    Engines::ResourcesManager::_duplicate(_ResManager);
421  return resManager._retn();
422 }
423
424
425 //=============================================================================
426 /*! Protected -
427  *  Find and aready existing and registered component instance.
428  *  \param params         machine parameters like type or name...
429  *  \param componentName  the name of component class
430  *  \param studyId        default = 0  : multistudy instance
431  *  \param listOfMachines list of machine address
432  *  \return a CORBA reference of the component instance, or _nil if not found
433  * - build a list of machines on which an instance of the component is running,
434  * - find the best machine among the list
435  */
436 //=============================================================================
437
438 Engines::Component_ptr
439 SALOME_LifeCycleCORBA::
440 _FindComponent(const Engines::MachineParameters& params,
441                const char *componentName,
442                int studyId,
443                const Engines::MachineList& listOfMachines)
444 {
445   // --- build the list of machines on which the component is already running
446
447   const char *containerName = params.container_name;
448   int nbproc = NbProc(params);
449 //   MESSAGE("_FindComponent, required " << containerName <<
450 //        " " << componentName << " " << nbproc);
451
452   Engines::MachineList_var machinesOK = new Engines::MachineList;
453
454   unsigned int lghtOfmachinesOK = 0;
455   machinesOK->length(listOfMachines.length());
456
457   for(unsigned int i=0; i<listOfMachines.length(); i++)
458     {
459       const char *currentMachine=listOfMachines[i];
460 //       MESSAGE("_FindComponent, look at " << currentMachine);
461       CORBA::Object_var obj = _NS->ResolveComponent(currentMachine,
462                                                     containerName,
463                                                     componentName,
464                                                     nbproc);
465       if (!CORBA::is_nil(obj))
466         machinesOK[lghtOfmachinesOK++] = CORBA::string_dup(currentMachine);
467     }
468
469   // --- find the best machine among the list
470
471   if(lghtOfmachinesOK != 0)
472     {
473       machinesOK->length(lghtOfmachinesOK);
474       CORBA::String_var bestMachine = _ResManager->FindFirst(machinesOK);
475       CORBA::Object_var obj = _NS->ResolveComponent(bestMachine,
476                                                     containerName,
477                                                     componentName,
478                                                     nbproc);
479       return Engines::Component::_narrow(obj);
480     }
481   else
482     return Engines::Component::_nil();
483 }
484
485 //=============================================================================
486 /*! Protected -
487  *  Load a component instance.
488  *  \param params         machine parameters like type or name...
489  *  \param componentName  the name of component class
490  *  \param studyId        default = 0  : multistudy instance
491  *  \param listOfMachines list of machine address
492  *  \return a CORBA reference of the component instance, or _nil if problem
493  *  - Finds a container in the list of machine or start one.
494  *  - Try to load the component library in the container,
495  *  - then create an instance of the component.
496  */
497 //=============================================================================
498
499 Engines::Component_ptr 
500 SALOME_LifeCycleCORBA::
501 _LoadComponent(const Engines::MachineParameters& params, 
502               const char *componentName,
503               int studyId,
504               const Engines::MachineList& listOfMachines)
505 {
506   const char *containerName = params.container_name;
507   int nbproc = NbProc(params);
508
509   MESSAGE("_LoadComponent, required " << containerName <<
510           " " << componentName << " " << nbproc);
511
512   Engines::Container_var cont =
513     _ContManager->FindOrStartContainer(params,
514                                        listOfMachines);
515   if (CORBA::is_nil(cont)) return Engines::Component::_nil();
516
517   bool isLoadable = cont->load_component_Library(componentName);
518   if (!isLoadable) return Engines::Component::_nil();
519
520   Engines::Component_var myInstance =
521     cont->create_component_instance(componentName, studyId);
522   return myInstance._retn();
523 }
524
525 Engines::Component_ptr
526 SALOME_LifeCycleCORBA::Load_ParallelComponent(const Engines::MachineParameters& params,
527                                               const char *componentName,
528                                               int studyId)
529 {
530   MESSAGE("Entering LoadParallelComponent");
531
532 /*MESSAGE("Parameters : ");
533   MESSAGE("Container name : " << params.container_name);
534   MESSAGE("Number of component nodes : " << params.nb_component_nodes);
535   MESSAGE("Component Name : " << componentName);*/
536
537   Engines::CompoList clist;
538   clist.length(1);
539   clist[0] = componentName;
540   MESSAGE("Building a list of machines");
541   Engines::MachineList_var listOfMachines = _ResManager->GetFittingResources(params, clist);
542   if (listOfMachines->length() == 0)
543   {
544     INFOS("No matching machines founded !");
545     return Engines::Component::_nil();
546   }
547
548   MESSAGE("Starting Parallel Container");
549   Engines::Container_var cont = _ContManager->FindOrStartParallelContainer(params, listOfMachines);
550   if (CORBA::is_nil(cont)) {
551     INFOS("FindOrStartParallelContainer() returns a NULL container !");
552     return Engines::Component::_nil();
553   }
554
555   MESSAGE("Loading component library");
556   bool isLoadable = cont->load_component_Library(componentName);
557   if (!isLoadable) {
558     INFOS(componentName <<" library is not loadable !");
559     return Engines::Component::_nil();
560   }
561
562   MESSAGE("Creating component instance");
563   // @PARALLEL@ permits to identify that the component requested
564   // is a parallel component.
565   string name = string(componentName) + string("@PARALLEL@");
566   Engines::Component_var myInstance = cont->create_component_instance(name.c_str(), studyId);
567   if (CORBA::is_nil(myInstance))
568     INFOS("create_component_instance returns a NULL component !");
569   return myInstance._retn();
570 }
571