]> SALOME platform Git repositories - modules/kernel.git/blob - src/LifeCycleCORBA/SALOME_LifeCycleCORBA.cxx
Salome HOME
CCAR:
[modules/kernel.git] / src / LifeCycleCORBA / SALOME_LifeCycleCORBA.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, 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.
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 //  SALOME LifeCycleCORBA : implementation of containers and engines life cycle both in Python and C++
23 //  File   : SALOME_LifeCycleCORBA.cxx
24 //  Author : Paul RASCLE, EDF
25 //  Module : SALOME
26 //  $Header$
27 //
28 #include <iostream>
29 #include <fstream>
30 #include <sstream>
31 #include <iomanip>
32
33 #include <time.h>
34 #ifndef WIN32
35   #include <sys/time.h>
36 #endif
37
38 #include "Basics_Utils.hxx"
39 #include "utilities.h"
40
41 #include <ServiceUnreachable.hxx>
42
43 #include "SALOME_LifeCycleCORBA.hxx"
44 #include CORBA_CLIENT_HEADER(SALOME_ModuleCatalog)
45 #include CORBA_CLIENT_HEADER(SALOME_Session)
46 #include CORBA_CLIENT_HEADER(DSC_Engines)
47 #include CORBA_CLIENT_HEADER(SALOME_Registry)
48 #include CORBA_CLIENT_HEADER(SALOMEDS)
49 #include CORBA_CLIENT_HEADER(Logger)
50
51 #include "SALOME_ContainerManager.hxx"
52 #include "SALOME_Component_i.hxx"
53 #include "SALOME_NamingService.hxx"
54
55 using namespace std;
56
57 IncompatibleComponent::IncompatibleComponent( void ):
58   SALOME_Exception( "IncompatibleComponent" )
59 {
60 }
61
62 IncompatibleComponent::IncompatibleComponent(const IncompatibleComponent &ex):
63   SALOME_Exception( ex ) 
64 {
65 }
66
67 /*! \class SALOME_LifeCycleCORBA
68     \brief A class to manage life cycle of SALOME components.
69
70 */
71
72 //=============================================================================
73 /*! 
74  *  Constructor
75  */
76 //=============================================================================
77
78 SALOME_LifeCycleCORBA::SALOME_LifeCycleCORBA(SALOME_NamingService *ns)
79 {
80   // be sure to have an instance of traceCollector, when used via SWIG
81   // in a Python module
82   int argc = 0;
83   char *xargv = (char*)"";
84   char **argv = &xargv;
85   CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
86   //  LocalTraceCollector *myThreadTrace = SALOMETraceCollector::instance(orb);
87   if (!ns)
88     {
89       _NS = new SALOME_NamingService(orb);
90     }
91   else _NS = ns;
92   //add try catch
93   _NS->Change_Directory("/"); // mpv 250105: current directory may be not root 
94                               // (in SALOMEDS for an example)
95   // not enough: set a current directory in naming service is not thread safe
96   // if naming service instance is shared among several threads...
97   // ==> allways use absolute path and dot rely on current directory!
98
99   CORBA::Object_var obj =
100     _NS->Resolve(SALOME_ContainerManager::_ContainerManagerNameInNS);
101   ASSERT( !CORBA::is_nil(obj));
102   _ContManager=Engines::ContainerManager::_narrow(obj);
103
104   obj = _NS->Resolve(SALOME_ResourcesManager::_ResourcesManagerNameInNS);
105   ASSERT( !CORBA::is_nil(obj));
106   _ResManager=Engines::ResourcesManager::_narrow(obj);
107 }
108
109 //=============================================================================
110 /*! 
111  *  Destructor
112  */
113 //=============================================================================
114
115 SALOME_LifeCycleCORBA::~SALOME_LifeCycleCORBA()
116 {
117 }
118
119 //=============================================================================
120 /*! \brief Find an already existing and registered component instance.
121  *
122  *  \param params         machine parameters like type or name...
123  *  \param componentName  the name of component class
124  *  \param studyId        default = 0  : multistudy instance
125  *  \return a CORBA reference of the component instance, or _nil if not found
126  */
127 //=============================================================================
128 Engines::Component_ptr
129 SALOME_LifeCycleCORBA::FindComponent(const Engines::MachineParameters& params,
130                                      const char *componentName,
131                                      int studyId)
132 {
133   if (! isKnownComponentClass(componentName))
134     return Engines::Component::_nil();
135
136   Engines::CompoList clist;
137   clist.length(1);
138   clist[0] = componentName;
139   Engines::MachineList_var listOfMachines =
140     _ResManager->GetFittingResources(params, clist);
141
142   Engines::Component_var compo = _FindComponent(params,
143                                                 componentName,
144                                                 studyId,
145                                                 listOfMachines);
146
147   return compo._retn();
148 }
149
150 //=============================================================================
151 /*! \brief Load a component instance on a container defined by machine parameters
152  *
153  *  \param params         machine parameters like type or name...
154  *  \param componentName  the name of component class
155  *  \param studyId        default = 0  : multistudy instance
156  *  \return a CORBA reference of the component instance, or _nil if problem
157  */
158 //=============================================================================
159
160 Engines::Component_ptr
161 SALOME_LifeCycleCORBA::LoadComponent(const Engines::MachineParameters& params,
162                                      const char *componentName,
163                                      int studyId)
164 {
165   // --- Check if Component Name is known in ModuleCatalog
166
167   if (! isKnownComponentClass(componentName))
168     return Engines::Component::_nil();
169
170   Engines::CompoList clist;
171   clist.length(1);
172   clist[0] = componentName;
173   Engines::MachineList_var listOfMachines =
174     _ResManager->GetFittingResources(params, clist);
175
176   Engines::Component_var compo = _LoadComponent(params,
177                                                 componentName,
178                                                 studyId,
179                                                 listOfMachines);
180
181   return compo._retn();
182 }
183
184 //=============================================================================
185 /*! \brief Find an already existing and registered component instance or load a new
186  *         component instance on a container defined by machine parameters.
187  *
188  *  \param params         machine parameters like type or name...
189  *  \param componentName  the name of component class
190  *  \param studyId        default = 0  : multistudy instance
191  *  \return a CORBA reference of the component instance, or _nil if problem
192  */
193 //=============================================================================
194
195 Engines::Component_ptr
196 SALOME_LifeCycleCORBA::
197 FindOrLoad_Component(const Engines::MachineParameters& params,
198                      const char *componentName,
199                      int studyId)
200 {
201   // --- Check if Component Name is known in ModuleCatalog
202
203   if (! isKnownComponentClass(componentName))
204     return Engines::Component::_nil();
205
206   Engines::CompoList clist;
207   clist.length(1);
208   clist[0] = componentName;
209   Engines::MachineList_var listOfMachines =
210     _ResManager->GetFittingResources(params,clist);
211
212   Engines::Component_var compo = _FindComponent(params,
213                                                 componentName,
214                                                 studyId,
215                                                 listOfMachines);
216
217   if(CORBA::is_nil(compo))
218     compo = _LoadComponent(params,
219                            componentName,
220                            studyId,
221                            listOfMachines);
222
223   return compo._retn();
224 }
225
226 //=============================================================================
227 /*! \brief Find an already existing and registered component instance or load a new
228  *         component instance on a container defined by name
229  *
230  *  \param containerName  the name of container, under one of the forms
231  *           - 1 aContainer (local container)
232  *           - 2 machine/aContainer (container on hostname = machine)
233  *  \param componentName  the name of component class
234  *  \return a CORBA reference of the component instance, or _nil if problem
235  */
236 //=============================================================================
237
238 Engines::Component_ptr
239 SALOME_LifeCycleCORBA::FindOrLoad_Component(const char *containerName,
240                                             const char *componentName)
241 {
242   char *valenv=getenv("SALOME_BATCH");
243   if(valenv)
244     if (strcmp(valenv,"1")==0)
245       {
246         MESSAGE("SALOME_LifeCycleCORBA::FindOrLoad_Component BATCH " << containerName << " " << componentName ) ;
247         _NS->Change_Directory("/Containers");
248         CORBA::Object_ptr obj=_NS->Resolve(containerName);
249         Engines::Container_var cont=Engines::Container::_narrow(obj);
250         bool isLoadable = cont->load_component_Library(componentName);
251         if (!isLoadable) return Engines::Component::_nil();
252         
253         Engines::Component_ptr myInstance =
254           cont->create_component_instance(componentName, 0);
255         return myInstance;
256       }
257   MESSAGE("SALOME_LifeCycleCORBA::FindOrLoad_Component INTERACTIF " << containerName << " " << componentName ) ;
258   //#if 0
259   // --- Check if Component Name is known in ModuleCatalog
260
261   if (! isKnownComponentClass(componentName))
262     return Engines::Component::_nil();
263
264   // --- Check if containerName contains machine name (if yes: rg>0)
265
266   char *stContainer=strdup(containerName);
267   string st2Container(stContainer);
268   int rg=st2Container.find("/");
269
270   Engines::MachineParameters_var params=new Engines::MachineParameters;
271   preSet(params);
272   if (rg<0)
273     {
274       // containerName doesn't contain "/" => Local container
275       params->container_name=CORBA::string_dup(stContainer);
276       params->hostname=CORBA::string_dup(Kernel_Utils::GetHostname().c_str());
277     }
278   else 
279     {
280       stContainer[rg]='\0';
281       params->container_name=CORBA::string_dup(stContainer+rg+1);
282       params->hostname=CORBA::string_dup(stContainer);
283     }
284   params->isMPI = false;
285   SCRUTE(params->container_name);
286 //   SCRUTE(params->hostname);
287 //   SCRUTE(params->OS);
288 //   SCRUTE(params->mem_mb);
289 //   SCRUTE(params->cpu_clock);
290 //   SCRUTE(params->nb_proc_per_node);
291 //   SCRUTE(params->nb_node);
292 //   SCRUTE(params->isMPI);
293   free(stContainer);
294   return FindOrLoad_Component(params,componentName);
295   //#endif  
296 }
297
298 //=============================================================================
299 /*! \brief Check if the component class is known in module catalog
300  *
301  *  \param componentName  the name of component class
302  *  \return true if found, false otherwise
303  */
304 //=============================================================================
305
306 bool SALOME_LifeCycleCORBA::isKnownComponentClass(const char *componentName)
307 {
308
309   try
310     {
311       CORBA::Object_var obj = _NS->Resolve("/Kernel/ModulCatalog");
312       SALOME_ModuleCatalog::ModuleCatalog_var Catalog = 
313         SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj) ;
314       ASSERT(! CORBA::is_nil(Catalog));
315       SALOME_ModuleCatalog::Acomponent_var compoInfo = 
316         Catalog->GetComponent(componentName);
317       if (CORBA::is_nil (compoInfo)) 
318         {
319           INFOS("Catalog Error: Component not found in the catalog" );
320           INFOS( componentName );         
321           return false;
322         }
323       else return true;
324     }
325   catch (ServiceUnreachable&)
326     {
327       INFOS("Caught exception: Naming Service Unreachable");
328     }
329   catch (...)
330     {
331       INFOS("Caught unknown exception.");
332     }
333   return false;
334 }
335
336 //=============================================================================
337 /*! 
338  *  Not so complex... useful ?
339  */
340 //=============================================================================
341
342 bool 
343 SALOME_LifeCycleCORBA::isMpiContainer(const Engines::MachineParameters& params)
344   throw(IncompatibleComponent)
345 {
346   if( params.isMPI )
347     return true;
348   else
349     return false;
350 }
351
352
353 //=============================================================================
354 /*! \brief Initialisation of a given Engines::MachineParameters with default values.
355  *
356  *  - container_name = ""  : not relevant
357  *  - hostname = ""        : not relevant
358  *  - OS = ""              : not relevant
359  *  - mem_mb = 0           : not relevant
360  *  - cpu_clock = 0        : not relevant
361  *  - nb_proc_per_node = 0 : not relevant
362  *  - nb_node = 0          : not relevant
363  *  - isMPI = false        : standard components
364  */
365 //=============================================================================
366
367 void SALOME_LifeCycleCORBA::preSet( Engines::MachineParameters& params)
368 {
369   params.container_name = "";
370   params.hostname = "";
371   params.OS = "";
372   params.mem_mb = 0;
373   params.cpu_clock = 0;
374   params.nb_proc_per_node = 0;
375   params.nb_node = 0;
376   params.isMPI = false;
377
378   params.parallelLib = "";
379   params.nb_component_nodes = 0;
380 }
381
382 //=============================================================================
383 /*! 
384  *  \return a number of processors not 0, only for MPI containers
385  */
386 //=============================================================================
387
388 int SALOME_LifeCycleCORBA::NbProc(const Engines::MachineParameters& params)
389 {
390   if( !isMpiContainer(params) )
391     return 0;
392   else if( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
393     return 1;
394   else if( params.nb_node == 0 )
395     return params.nb_proc_per_node;
396   else if( params.nb_proc_per_node == 0 )
397     return params.nb_node;
398   else
399     return params.nb_node * params.nb_proc_per_node;
400 }
401
402 //=============================================================================
403 /*! \brief Get the container manager
404  *
405  *  \return the container Manager
406  */
407 //=============================================================================
408
409 Engines::ContainerManager_ptr SALOME_LifeCycleCORBA::getContainerManager()
410 {
411  Engines::ContainerManager_var contManager =
412    Engines::ContainerManager::_duplicate(_ContManager);
413  return contManager._retn();
414 }
415
416 //=============================================================================
417 /*! \brief Get the resources manager
418  *
419  *  \return the container Manager
420  */
421 //=============================================================================
422
423 Engines::ResourcesManager_ptr SALOME_LifeCycleCORBA::getResourcesManager()
424 {
425  Engines::ResourcesManager_var resManager =
426    Engines::ResourcesManager::_duplicate(_ResManager);
427  return resManager._retn();
428 }
429
430 //=============================================================================
431 /*! \brief shutdown all the SALOME servers except SALOME_Session_Server, omniNames and notifd
432  */
433 //=============================================================================
434
435 void SALOME_LifeCycleCORBA::shutdownServers()
436 {
437   // get each Container from NamingService => shutdown it
438   // (the order is inverse to the order of servers initialization)
439   
440   SALOME::Session_var session = SALOME::Session::_nil();
441   CORBA::Long pid = 0;
442   CORBA::Object_var objS = _NS->Resolve("/Kernel/Session");
443   if (!CORBA::is_nil(objS))
444     {
445       session = SALOME::Session::_narrow(objS);
446       if (!CORBA::is_nil(session))
447         {
448           pid = session->getPID();
449           session->ping();
450         }
451     }
452
453   string hostname = Kernel_Utils::GetHostname();
454   
455   // 1) SalomeLauncher
456   CORBA::Object_var objSL = _NS->Resolve("/SalomeLauncher");
457   Engines::SalomeLauncher_var launcher = Engines::SalomeLauncher::_narrow(objSL);
458   if (!CORBA::is_nil(launcher) && (pid != launcher->getPID()))
459     launcher->Shutdown();
460   
461   // 2) ConnectionManager
462   CORBA::Object_var objCnM=_NS->Resolve("/ConnectionManager");
463   Engines::ConnectionManager_var connMan=Engines::ConnectionManager::_narrow(objCnM);
464   if ( !CORBA::is_nil(connMan) && ( pid != connMan->getPID() ) )
465     connMan->ShutdownWithExit();
466   
467   // 3) SALOMEDS
468   CORBA::Object_var objSDS = _NS->Resolve("/myStudyManager");
469   SALOMEDS::StudyManager_var studyManager = SALOMEDS::StudyManager::_narrow(objSDS) ;
470   if ( !CORBA::is_nil(studyManager) && ( pid != studyManager->getPID() ) )
471     studyManager->Shutdown();
472   
473   // 4) ModuleCatalog
474   CORBA::Object_var objMC=_NS->Resolve("/Kernel/ModulCatalog");
475   SALOME_ModuleCatalog::ModuleCatalog_var catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(objMC);
476   if ( !CORBA::is_nil(catalog) && ( pid != catalog->getPID() ) )
477     catalog->shutdown();
478   
479   // 5) Registry
480   CORBA::Object_var objR = _NS->Resolve("/Registry");
481   Registry::Components_var registry = Registry::Components::_narrow(objR);
482   if ( !CORBA::is_nil(registry) && ( pid != registry->getPID() ) )
483       registry->Shutdown();
484
485   // 6) Logger
486   int argc = 0;
487   char *xargv = (char*)"";
488   char **argv = &xargv;
489   CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
490
491   CORBA::Object_var objLog = CORBA::Object::_nil();
492   CosNaming::NamingContext_var inc;
493   CORBA::Object_var theObj = CORBA::Object::_nil();
494   std::string stdname = "Logger";
495   CosNaming::Name name;
496   name.length(1);
497   name[0].id = CORBA::string_dup(stdname.c_str());
498   try
499     { 
500       if(!CORBA::is_nil(orb)) 
501         theObj = orb->resolve_initial_references("NameService");
502       if (!CORBA::is_nil(theObj))
503         inc = CosNaming::NamingContext::_narrow(theObj);
504     }
505   catch(...)
506     {
507     }
508   if(!CORBA::is_nil(inc)) {
509     try
510       {
511         objLog = inc->resolve(name);
512         SALOME_Logger::Logger_var logger = SALOME_Logger::Logger::_narrow(objLog);
513         if ( !CORBA::is_nil(logger) )
514           logger->shutdown();
515       }
516     catch(...)
517       {
518       }
519   }
520 }
521
522 //=============================================================================
523 /*! \brief shutdown  omniNames and notifd
524  */
525 //=============================================================================
526
527 void SALOME_LifeCycleCORBA::killOmniNames()
528 {
529   string portNumber (::getenv ("NSPORT") );
530   if ( !portNumber.empty() ) 
531     {
532       string cmd ;
533       cmd = string( "ps -eo pid,command | grep -v grep | grep -E \"omniNames.*")
534         + portNumber
535         + string("\" | awk '{cmd=sprintf(\"kill -9 %s\",$1); system(cmd)}'" );
536       MESSAGE(cmd);
537       try {
538         system ( cmd.c_str() );
539       }
540       catch ( ... ) {
541       }
542     }
543   
544   // NPAL 18309  (Kill Notifd)
545   if ( !portNumber.empty() ) 
546     {
547       string cmd = ("from killSalomeWithPort import killNotifdAndClean; ");
548       cmd += string("killNotifdAndClean(") + portNumber + "); ";
549       cmd  = string("python -c \"") + cmd +"\" >& /dev/null";
550       MESSAGE(cmd);
551       system( cmd.c_str() );
552     }
553 }
554
555 //=============================================================================
556 /*! \brief Find an already existing and registered component instance.
557  *
558  * - build a list of machines on which an instance of the component is running,
559  * - find the best machine among the list
560  *
561  *  \param params         machine parameters like type or name...
562  *  \param componentName  the name of component class
563  *  \param studyId        default = 0  : multistudy instance
564  *  \param listOfMachines list of machine address
565  *  \return a CORBA reference of the component instance, or _nil if not found
566  */
567 //=============================================================================
568
569 Engines::Component_ptr
570 SALOME_LifeCycleCORBA::
571 _FindComponent(const Engines::MachineParameters& params,
572                const char *componentName,
573                int studyId,
574                const Engines::MachineList& listOfMachines)
575 {
576   // --- build the list of machines on which the component is already running
577
578   const char *containerName = params.container_name;
579   int nbproc = NbProc(params);
580 //   MESSAGE("_FindComponent, required " << containerName <<
581 //        " " << componentName << " " << nbproc);
582
583   Engines::MachineList_var machinesOK = new Engines::MachineList;
584
585   unsigned int lghtOfmachinesOK = 0;
586   machinesOK->length(listOfMachines.length());
587
588   for(unsigned int i=0; i<listOfMachines.length(); i++)
589     {
590       const char *currentMachine=listOfMachines[i];
591 //       MESSAGE("_FindComponent, look at " << currentMachine);
592       CORBA::Object_var obj = _NS->ResolveComponent(currentMachine,
593                                                     containerName,
594                                                     componentName,
595                                                     nbproc);
596       if (!CORBA::is_nil(obj))
597         machinesOK[lghtOfmachinesOK++] = CORBA::string_dup(currentMachine);
598     }
599
600   // --- find the best machine among the list
601
602   if(lghtOfmachinesOK != 0)
603     {
604       machinesOK->length(lghtOfmachinesOK);
605       CORBA::String_var bestMachine = _ResManager->FindFirst(machinesOK);
606       CORBA::Object_var obj = _NS->ResolveComponent(bestMachine,
607                                                     containerName,
608                                                     componentName,
609                                                     nbproc);
610       return Engines::Component::_narrow(obj);
611     }
612   else
613     return Engines::Component::_nil();
614 }
615
616 //=============================================================================
617 /*! \brief  Load a component instance.
618  *
619  *  - Finds a container in the list of machine or start one.
620  *  - Try to load the component library in the container,
621  *  - then create an instance of the component.
622  *
623  *  \param params         machine parameters like type or name...
624  *  \param componentName  the name of component class
625  *  \param studyId        default = 0  : multistudy instance
626  *  \param listOfMachines list of machine address
627  *  \return a CORBA reference of the component instance, or _nil if problem
628  */
629 //=============================================================================
630
631 Engines::Component_ptr 
632 SALOME_LifeCycleCORBA::
633 _LoadComponent(const Engines::MachineParameters& params, 
634               const char *componentName,
635               int studyId,
636               const Engines::MachineList& listOfMachines)
637 {
638   MESSAGE("_LoadComponent, required " << params.container_name <<
639           " " << componentName << " " << NbProc(params));
640
641   Engines::Container_var cont =
642     _ContManager->FindOrStartContainer(params,
643                                        listOfMachines);
644   if (CORBA::is_nil(cont)) return Engines::Component::_nil();
645
646   bool isLoadable = cont->load_component_Library(componentName);
647   if (!isLoadable) return Engines::Component::_nil();
648
649   Engines::Component_var myInstance =
650     cont->create_component_instance(componentName, studyId);
651   return myInstance._retn();
652 }
653
654 //=============================================================================
655 /*! \brief  Load a parallel component instance.
656  *
657  *  \param params         machine parameters like type or name...
658  *  \param componentName  the name of component class
659  *  \param studyId        default = 0  : multistudy instance
660  *  \return a CORBA reference of the parallel component instance, or _nil if problem
661  */
662 //=============================================================================
663 Engines::Component_ptr
664 SALOME_LifeCycleCORBA::Load_ParallelComponent(const Engines::MachineParameters& params,
665                                               const char *componentName,
666                                               int studyId)
667 {
668   MESSAGE("Entering LoadParallelComponent");
669
670 /*MESSAGE("Parameters : ");
671   MESSAGE("Container name : " << params.container_name);
672   MESSAGE("Number of component nodes : " << params.nb_component_nodes);
673   MESSAGE("Component Name : " << componentName);*/
674
675   Engines::CompoList clist;
676   clist.length(1);
677   clist[0] = componentName;
678   MESSAGE("Building a list of machines");
679   Engines::MachineList_var listOfMachines = _ResManager->GetFittingResources(params, clist);
680   if (listOfMachines->length() == 0)
681   {
682     INFOS("No matching machines founded !");
683     return Engines::Component::_nil();
684   }
685
686   MESSAGE("Starting Parallel Container");
687   Engines::Container_var cont = _ContManager->FindOrStartParallelContainer(params, listOfMachines);
688   if (CORBA::is_nil(cont)) {
689     INFOS("FindOrStartParallelContainer() returns a NULL container !");
690     return Engines::Component::_nil();
691   }
692
693   MESSAGE("Loading component library");
694   bool isLoadable = cont->load_component_Library(componentName);
695   if (!isLoadable) {
696     INFOS(componentName <<" library is not loadable !");
697     return Engines::Component::_nil();
698   }
699
700   MESSAGE("Creating component instance");
701   // @PARALLEL@ permits to identify that the component requested
702   // is a parallel component.
703   string name = string(componentName) + string("@PARALLEL@");
704   Engines::Component_var myInstance = cont->create_component_instance(name.c_str(), studyId);
705   if (CORBA::is_nil(myInstance))
706     INFOS("create_component_instance returns a NULL component !");
707   return myInstance._retn();
708 }
709