Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/yacs.git] / src / runtime / SalomeContainer.cxx
1 // Copyright (C) 2006-2012  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 //#define REFCNT
21 //
22 #ifdef REFCNT
23 #define private public
24 #define protected public
25 #include <omniORB4/CORBA.h>
26 #include <omniORB4/internal/typecode.h>
27 #endif
28
29 #include "RuntimeSALOME.hxx"
30 #include "SalomeContainer.hxx"
31 #include "SalomeComponent.hxx"
32 #include "Proc.hxx"
33
34 #include "SALOME_NamingService.hxx"
35 #include "SALOME_LifeCycleCORBA.hxx"
36 #include "SALOME_ContainerManager.hxx"
37 #include "Basics_Utils.hxx"
38 #include "OpUtil.hxx"
39
40 #include <sstream>
41 #include <iostream>
42
43 #ifdef WNT
44 #include <process.h>
45 #define getpid _getpid
46 #endif
47
48 //#define _DEVDEBUG_
49 #include "YacsTrace.hxx"
50
51 using namespace YACS::ENGINE;
52 using namespace std;
53
54 SalomeContainer::SalomeContainer():_trueCont(Engines::Container::_nil()),_type("mono"),_shutdownLevel(999)
55 {
56   /* Init ContainerParameters */
57   _params.container_name = "";
58   _params.mode= "start";
59   _params.workingdir= "";
60   _params.nb_proc = 0;
61   _params.isMPI = false;
62   _params.parallelLib = "";
63
64   _params.resource_params.name = "";
65   _params.resource_params.hostname = "";
66   _params.resource_params.OS = "";
67   _params.resource_params.nb_proc = 0;
68   _params.resource_params.mem_mb = 0;
69   _params.resource_params.cpu_clock = 0;
70   _params.resource_params.nb_node = 0;
71   _params.resource_params.nb_proc_per_node = 0;
72   _params.resource_params.policy = "";
73   // By default, componentList and resList length is 0
74 }
75
76 SalomeContainer::SalomeContainer(const SalomeContainer& other):Container(other),_trueCont(Engines::Container::_nil()),_type(other._type),
77                                                                                 _shutdownLevel(other._shutdownLevel)
78 {
79   _params.container_name = CORBA::string_dup(other._params.container_name);
80   _params.mode= CORBA::string_dup(other._params.mode);
81   _params.workingdir= CORBA::string_dup(other._params.workingdir);
82   _params.nb_proc = other._params.nb_proc;
83   _params.isMPI = other._params.isMPI;
84   _params.parallelLib = CORBA::string_dup(other._params.parallelLib);
85
86   _params.resource_params.name = CORBA::string_dup(other._params.resource_params.name);
87   _params.resource_params.hostname = CORBA::string_dup(other._params.resource_params.hostname);
88   _params.resource_params.OS = CORBA::string_dup(other._params.resource_params.OS);
89   _params.resource_params.nb_proc = other._params.resource_params.nb_proc;
90   _params.resource_params.mem_mb = other._params.resource_params.mem_mb;
91   _params.resource_params.cpu_clock = other._params.resource_params.cpu_clock;
92   _params.resource_params.nb_node = other._params.resource_params.nb_node;
93   _params.resource_params.nb_proc_per_node = other._params.resource_params.nb_proc_per_node;
94   _params.resource_params.policy = CORBA::string_dup(other._params.resource_params.policy);
95
96   _params.resource_params.componentList.length(other._params.resource_params.componentList.length());
97   for(CORBA::ULong i=0; i < other._params.resource_params.componentList.length(); i++)
98   {
99     _params.resource_params.componentList[i]=CORBA::string_dup(other._params.resource_params.componentList[i]);
100   }
101
102   _params.resource_params.resList.length(other._params.resource_params.resList.length());
103   for(CORBA::ULong i=0; i < other._params.resource_params.resList.length(); i++)
104   {
105     _params.resource_params.resList[i]=CORBA::string_dup(other._params.resource_params.resList[i]);
106   }
107 }
108
109 SalomeContainer::~SalomeContainer()
110 {
111 }
112
113 void SalomeContainer::lock()
114 {
115   _mutex.lock();
116 }
117
118 void SalomeContainer::unLock()
119 {
120   _mutex.unlock();
121 }
122
123 Container *SalomeContainer::clone() const
124 {
125   if(_isAttachedOnCloning)
126     {
127       incrRef();
128       return (Container*) (this);
129     }
130   else
131     return new SalomeContainer(*this);
132 }
133
134 void SalomeContainer::checkCapabilityToDealWith(const ComponentInstance *inst) const throw(YACS::Exception)
135 {
136   if(inst->getKind()!=SalomeComponent::KIND)
137     throw Exception("SalomeContainer::checkCapabilityToDealWith : SalomeContainer is not able to deal with this type of ComponentInstance.");
138 }
139
140 void SalomeContainer::setProperty(const std::string& name, const std::string& value)
141 {
142   DEBTRACE("SalomeContainer::setProperty : " << name << " ; " << value);
143    
144   // Container Part
145   if (name == "container_name")
146     _params.container_name = CORBA::string_dup(value.c_str());
147   else if (name == "type")
148   {
149     if (value == "mono")
150       _params.mode = "start";
151     else if (value == "multi")
152       _params.mode = "getorstart";
153     else 
154       throw Exception("SalomeContainer::setProperty : type value is not correct (mono or multi): " + value);
155     _type=value;
156   }
157   else if (name == "workingdir")
158     _params.workingdir = CORBA::string_dup(value.c_str());
159   else if (name == "nb_parallel_procs")
160   {
161     std::istringstream iss(value);
162     if (!(iss >> _params.nb_proc))
163       throw Exception("salomecontainer::setproperty : params.nb_proc value not correct : " + value);
164   }
165   else if (name == "isMPI")
166   {
167     if (value == "true")
168       _params.isMPI = true;
169     else if (value == "false")
170       _params.isMPI = false;
171     else 
172       throw Exception("SalomeContainer::setProperty : params.isMPI value not correct : " + value);
173   }
174   else if (name == "parallelLib")
175     _params.parallelLib = CORBA::string_dup(value.c_str());
176
177   // Resource part
178   else if (name == "name")
179     _params.resource_params.name = CORBA::string_dup(value.c_str());
180   else if (name == "hostname")
181     _params.resource_params.hostname = CORBA::string_dup(value.c_str());
182   else if (name == "OS")
183     _params.resource_params.OS = CORBA::string_dup(value.c_str());
184   else if (name == "nb_resource_procs")
185   {
186     std::istringstream iss(value);
187     if (!(iss >> _params.resource_params.nb_proc))
188       throw Exception("salomecontainer::setproperty : params.resource_params.nb_proc value not correct : " + value);
189   }
190   else if (name == "mem_mb")
191   {
192     std::istringstream iss(value);
193     if (!(iss >> _params.resource_params.mem_mb))
194       throw Exception("salomecontainer::setproperty : params.resource_params.mem_mb value not correct : " + value);
195   }
196   else if (name == "cpu_clock")
197   {
198     std::istringstream iss(value);
199     if (!(iss >> _params.resource_params.cpu_clock))
200       throw Exception("salomecontainer::setproperty : params.resource_params.cpu_clock value not correct : " + value);
201   }
202   else if (name == "nb_node")
203   {
204     std::istringstream iss(value);
205     if (!(iss >> _params.resource_params.nb_node))
206       throw Exception("salomecontainer::setproperty : params.nb_node value not correct : " + value);
207   }
208   else if (name == "nb_proc_per_node")
209   {
210     std::istringstream iss(value);
211     if (!(iss >> _params.resource_params.nb_proc_per_node))
212       throw Exception("salomecontainer::setproperty : params.nb_proc_per_node value not correct : " + value);
213   }
214   else if (name == "policy")
215     _params.resource_params.policy = CORBA::string_dup(value.c_str());
216   else if (name == "component_list")
217   {
218     std::string clean_value(value);
219
220     // Step 1: remove blanks
221     while(clean_value.find(" ") != std::string::npos)
222       clean_value = clean_value.erase(clean_value.find(" "), 1);
223
224     // Step 2: get values
225     while(!clean_value.empty())
226     {
227       std::string result("");
228       std::string::size_type loc = clean_value.find(",", 0);
229       if (loc != std::string::npos)
230       {
231         result = clean_value.substr(0, loc);
232         clean_value = clean_value.erase(0, loc+1);
233       }
234       else
235       {
236         result = clean_value;
237         clean_value.erase();
238       }
239       if (result != "," && result != "")
240       {
241         addToComponentList(result);
242       }
243     }
244
245   }
246   else if (name == "resource_list")
247   {
248     std::string clean_value(value);
249
250     // Step 1: remove blanks
251     while(clean_value.find(" ") != std::string::npos)
252       clean_value = clean_value.erase(clean_value.find(" "), 1);
253
254     // Step 2: get values
255     while(!clean_value.empty())
256     {
257       std::string result("");
258       std::string::size_type loc = clean_value.find(",", 0);
259       if (loc != std::string::npos)
260       {
261         result = clean_value.substr(0, loc);
262         clean_value = clean_value.erase(0, loc+1);
263       }
264       else
265       {
266         result = clean_value;
267         clean_value.erase();
268       }
269       if (result != "," && result != "")
270       {
271         addToResourceList(result);
272       }
273     }
274
275   }
276   // End
277   Container::setProperty(name, value);
278 }
279
280 void SalomeContainer::addComponentName(std::string name)
281 {
282   _componentNames.push_back(name);
283 }
284
285 //! Load a component instance in this container
286 /*!
287  * \param inst the component instance to load
288  */
289 CORBA::Object_ptr SalomeContainer::loadComponent(ComponentInstance *inst)
290 {
291   DEBTRACE("SalomeContainer::loadComponent ");
292   lock();//To be sure
293   if(!isAlreadyStarted(inst))
294     {
295       try
296         {
297           start(inst);
298         }
299       catch(Exception& e)
300         {
301           unLock();
302           throw e;
303         }
304     }
305   unLock();
306   lock();//To be sure
307   CORBA::Object_ptr objComponent=CORBA::Object::_nil();
308   std::string compoName=inst->getCompoName();
309   const char* componentName=compoName.c_str();
310   Engines::Container_var container;
311   if(_type=="multi")
312     container=_trueContainers[inst];
313   else
314     container=_trueCont;
315
316   char* reason;
317
318   bool isLoadable = container->load_component_Library(componentName, reason);
319   if (isLoadable)
320     {
321       CORBA::string_free(reason);
322       int studyid=1;
323       Proc* p=getProc();
324       if(p)
325         {
326           std::string value=p->getProperty("DefaultStudyID");
327           if(!value.empty())
328             studyid= atoi(value.c_str());
329         }
330       // prepare component instance properties
331       Engines::FieldsDict_var env = new Engines::FieldsDict;
332       std::map<std::string, std::string> properties = inst->getProperties();
333       if(p)
334         {
335           std::map<std::string,std::string> procMap=p->getProperties();
336           properties.insert(procMap.begin(),procMap.end());
337         }
338
339       std::map<std::string, std::string>::const_iterator itm;
340       env->length(properties.size());
341       int item=0;
342       for(itm = properties.begin(); itm != properties.end(); ++itm, item++)
343         {
344           DEBTRACE("envname="<<itm->first<<" envvalue="<< itm->second);
345           env[item].key= CORBA::string_dup(itm->first.c_str());
346           env[item].value <<= itm->second.c_str();
347         }
348
349       objComponent=container->create_component_instance_env(componentName, studyid, env, reason);
350     }
351
352   if(CORBA::is_nil(objComponent))
353     {
354       unLock();
355       std::string text="Error while trying to create a new component: component '"+ compoName;
356       text=text+"' is not installed or it's a wrong name";
357       text += '\n';
358       text += reason;
359       CORBA::string_free(reason);
360       throw Exception(text);
361     }
362   unLock();
363   return objComponent;
364 }
365
366 //! Get the container placement id for a component instance
367 /*!
368  * \param inst the component instance
369  * \return the placement id
370  */
371 std::string SalomeContainer::getPlacementId(const ComponentInstance *inst) const
372 {
373
374   if(isAlreadyStarted(inst))
375     {
376       Engines::Container_var container=_trueCont;
377       if(_type=="multi")
378         {
379           std::map<const ComponentInstance *, Engines::Container_var>::const_iterator found = _trueContainers.find(inst);
380           container=found->second;
381         }
382       const char *what="/";
383       CORBA::String_var corbaStr=container->name();
384       string ret(corbaStr);
385
386       //Salome FOREVER ...
387       std::string::size_type i=ret.find_first_of(what,0);
388       i=ret.find_first_of(what, i==std::string::npos ? i:i+1);
389       if(i!=std::string::npos)
390         return ret.substr(i+1);
391       return ret;
392     }
393   else
394     return "Not placed yet !!!";
395 }
396
397 //! Get the container full path for a component instance
398 /*!
399  * \param inst the component instance
400  * \return the full placement id
401  */
402 std::string SalomeContainer::getFullPlacementId(const ComponentInstance *inst) const
403 {
404
405   if(isAlreadyStarted(inst))
406     {
407       Engines::Container_var container=_trueCont;
408       if(_type=="multi")
409         {
410           std::map<const ComponentInstance *, Engines::Container_var>::const_iterator found = _trueContainers.find(inst);
411           container=found->second;
412         }
413       try
414         {
415           CORBA::String_var corbaStr=container->name();
416           string ret(corbaStr);
417           return ret;
418         }
419       catch(...)
420         {
421           return "Unknown_placement";
422         }
423     }
424   else
425     return "Not_placed_yet";
426 }
427
428 //! Check if the component instance container is already started
429 /*!
430  * \param inst the component instance
431  * \return true, if the container is already started, else false
432  */
433 bool SalomeContainer::isAlreadyStarted(const ComponentInstance *inst) const
434 {
435   if(_type=="mono")
436     {
437       if(CORBA::is_nil(_trueCont))
438         return false;
439       else
440         return true;
441     }
442   else
443     {
444       if(_trueContainers.count(inst)==0)
445         return false;
446       else
447         return true;
448     }
449 }
450
451 Engines::Container_ptr SalomeContainer::getContainerPtr(const ComponentInstance *inst) const
452 {
453   if(_type=="mono")
454     {
455       if(CORBA::is_nil(_trueCont))
456         return Engines::Container::_nil();
457       else
458         return Engines::Container::_duplicate(_trueCont);
459     }
460   else
461     {
462       if(_trueContainers.count(inst)==0)
463         return Engines::Container::_nil();
464       else
465         {
466           std::map<const ComponentInstance *,Engines::Container_var>::const_iterator iter=_trueContainers.find(inst);
467           return Engines::Container::_duplicate(iter->second);
468         }
469     }
470 }
471
472 //! Start a salome container (true salome container not yacs one) with given ContainerParameters (_params)
473 /*!
474  * \param inst the component instance
475  */
476 void SalomeContainer::start(const ComponentInstance *inst) throw(YACS::Exception)
477 {
478   CORBA::ORB_ptr orb=getSALOMERuntime()->getOrb();
479   SALOME_NamingService ns;
480   try
481     {
482       ns.init_orb(orb);
483     }
484   catch(SALOME_Exception& e)
485     {
486       throw Exception("SalomeContainer::start : Unable to contact the SALOME Naming Service");
487     }
488   CORBA::Object_var obj=ns.Resolve(SALOME_ContainerManager::_ContainerManagerNameInNS);
489   Engines::ContainerManager_var contManager=Engines::ContainerManager::_narrow(obj);
490
491   std::string str(_params.container_name);
492   DEBTRACE("SalomeContainer::start " << str <<";"<<_params.resource_params.hostname <<";"<<_type);
493
494   // Finalize parameters with components found in the container
495   std::vector<std::string>::iterator iter;
496   for(CORBA::ULong i=0; i < _componentNames.size();i++)
497     addToComponentList(_componentNames[i]);
498   Engines::ContainerParameters myparams = _params;
499
500   bool namedContainer=false;
501   if(str != "")
502     namedContainer=true;
503
504   //If a container_name is given try to find an already existing container in naming service
505   //If not found start a new container with the given parameters
506   if (_type=="mono" && str != "")
507     {
508       myparams.mode="getorstart";
509     }
510
511   if (str == "")
512   {
513     //give a almost unique name to the container : Pid_Name_Addr
514     std::ostringstream stream;
515     stream << getpid();
516     stream << "_";
517     stream << _name;
518     stream << "_";
519     stream << (void *)(this);
520     DEBTRACE("container_name="<<stream.str());
521     myparams.container_name=CORBA::string_dup(stream.str().c_str());
522     _shutdownLevel=1;
523   }
524
525   _trueCont=Engines::Container::_nil();
526   if(namedContainer && _shutdownLevel==999)
527     {
528       //Make this only the first time start is called (_shutdownLevel==999)
529       //If the container is named, first try to get an existing container
530       //If there is an existing container use it and set the shutdown level to 3
531       //If there is no existing container, try to launch a new one and set the shutdown level to 2
532       myparams.mode="get";
533       try
534         { 
535           _trueCont=contManager->GiveContainer(myparams);
536         }
537       catch( const SALOME::SALOME_Exception& ex )
538         {
539           std::string msg="SalomeContainer::start : no existing container : ";
540           msg += '\n';
541           msg += ex.details.text.in();
542           DEBTRACE( msg );
543         }
544       catch(...)
545         {
546         }
547
548       if(!CORBA::is_nil(_trueCont))
549         {
550           _shutdownLevel=3;
551           DEBTRACE( "container found: " << str << " " << _shutdownLevel );
552         }
553       else
554         {
555           _shutdownLevel=2;
556           myparams.mode="start";
557           DEBTRACE( "container not found: " << str << " " << _shutdownLevel);
558         }
559     }
560
561   if(CORBA::is_nil(_trueCont))
562     try
563       { 
564         // --- GiveContainer is used in batch mode to retreive launched containers,
565         //     and is equivalent to StartContainer when not in batch.
566         _trueCont=contManager->GiveContainer(myparams);
567       }
568     catch( const SALOME::SALOME_Exception& ex )
569       {
570         std::string msg="SalomeContainer::start : Unable to launch container in Salome : ";
571         msg += '\n';
572         msg += ex.details.text.in();
573         throw Exception(msg);
574       }
575     catch(CORBA::COMM_FAILURE&)
576       {
577         throw Exception("SalomeContainer::start : Unable to launch container in Salome : CORBA Comm failure detected");
578       }
579     catch(CORBA::Exception&)
580       {
581         throw Exception("SalomeContainer::start : Unable to launch container in Salome : Unexpected CORBA failure detected");
582       }
583
584   if(CORBA::is_nil(_trueCont))
585     throw Exception("SalomeContainer::start : Unable to launch container in Salome. Check your CatalogResources.xml file");
586
587   _trueContainers[inst]=_trueCont;
588
589   CORBA::String_var containerName=_trueCont->name();
590   CORBA::String_var hostName=_trueCont->getHostName();
591   std::cerr << "SalomeContainer launched : " << containerName << " " << hostName << " " << _trueCont->getPID() << std::endl;
592
593 #ifdef REFCNT
594     DEBTRACE(_trueCont->_PR_getobj()->pd_refCount );
595     std::map<const ComponentInstance *, Engines::Container_var >::const_iterator it;
596     for(it = _trueContainers.begin(); it != _trueContainers.end(); ++it)
597       {
598         DEBTRACE(it->second->_PR_getobj()->pd_refCount );
599       }
600 #endif
601 }
602
603 void SalomeContainer::shutdown(int level)
604 {
605   DEBTRACE("SalomeContainer::shutdown: " << _name << "," << level << "," << _shutdownLevel);
606   if(level < _shutdownLevel)
607     return;
608
609   _shutdownLevel=999;
610   //shutdown the SALOME containers
611   if(_type=="multi")
612     {
613       std::map<const ComponentInstance *, Engines::Container_var >::const_iterator it;
614       for(it = _trueContainers.begin(); it != _trueContainers.end(); ++it)
615         {
616           try
617             {
618               DEBTRACE("shutdown SALOME container: " );
619               CORBA::String_var containerName=it->second->name();
620               DEBTRACE(containerName);
621               it->second->Shutdown();
622               std::cerr << "shutdown SALOME container: " << containerName << std::endl;
623             }
624           catch(CORBA::Exception&)
625             {
626               DEBTRACE("Unexpected CORBA failure detected." );
627             }
628           catch(...)
629             {
630               DEBTRACE("Unknown exception ignored." );
631             }
632         }
633       _trueContainers.clear();
634     }
635   else
636     {
637       try
638         {
639           DEBTRACE("shutdown SALOME container: " );
640           CORBA::String_var containerName=_trueCont->name();
641           DEBTRACE(containerName);
642           _trueCont->Shutdown();
643           std::cerr << "shutdown SALOME container: " << containerName << std::endl;
644         }
645       catch(...)
646         {
647           DEBTRACE("Unknown exception ignored." );
648         }
649       _trueCont=Engines::Container::_nil();
650     }
651 }
652
653 void
654 SalomeContainer::addToComponentList(const std::string & name)
655 {
656   // Search if name is already in the list
657   for (CORBA::ULong i = 0; i < _params.resource_params.componentList.length(); i++)
658   {
659     std::string component_name = _params.resource_params.componentList[i].in();
660     if (component_name == name)
661       return;
662   }
663
664   // Add name to list
665   CORBA::ULong lgth = _params.resource_params.componentList.length();
666   _params.resource_params.componentList.length(lgth + 1);
667   _params.resource_params.componentList[lgth] = CORBA::string_dup(name.c_str());
668 }
669
670 void
671 SalomeContainer::addToResourceList(const std::string & name)
672 {
673   // Search if name is already in the list
674   for (CORBA::ULong i = 0; i < _params.resource_params.resList.length(); i++)
675   {
676     std::string component_name = _params.resource_params.resList[i].in();
677     if (component_name == name)
678       return;
679   }
680
681   // Add name to list
682   CORBA::ULong lgth = _params.resource_params.resList.length();
683   _params.resource_params.resList.length(lgth + 1);
684   _params.resource_params.resList[lgth] = CORBA::string_dup(name.c_str());
685 }
686
687 std::map<std::string,std::string> SalomeContainer::getResourceProperties(const std::string& name)
688 {
689   std::map<std::string,std::string> properties;
690
691   YACS::ENGINE::RuntimeSALOME* runTime = YACS::ENGINE::getSALOMERuntime();
692   CORBA::ORB_ptr orb = runTime->getOrb();
693   if (!orb) return properties;
694   SALOME_NamingService namingService(orb);
695   SALOME_LifeCycleCORBA lcc(&namingService);
696   CORBA::Object_var obj = namingService.Resolve(SALOME_ResourcesManager::_ResourcesManagerNameInNS);
697   if (CORBA::is_nil(obj)) return properties;
698   Engines::ResourcesManager_var resManager = Engines::ResourcesManager::_narrow(obj);
699   if (CORBA::is_nil(resManager)) return properties;
700
701   std::ostringstream value;
702   Engines::ResourceDefinition_var resource_definition = resManager->GetResourceDefinition(name.c_str());
703   properties["hostname"]=resource_definition->hostname.in();
704   properties["OS"]=resource_definition->OS.in();
705   value.str(""); value << resource_definition->mem_mb;
706   properties["mem_mb"]=value.str();
707   value.str(""); value << resource_definition->cpu_clock;
708   properties["cpu_clock"]=value.str();
709   value.str(""); value << resource_definition->nb_node;
710   properties["nb_node"]=value.str();
711   value.str(""); value << resource_definition->nb_proc_per_node;
712   properties["nb_proc_per_node"]=value.str();
713   /*
714   properties["component_list"]="";
715   for(CORBA::ULong i=0; i < resource_definition->componentList.length(); i++)
716     {
717       if(i > 0)
718         properties["component_list"]=properties["component_list"]+",";
719       properties["component_list"]=properties["component_list"]+resource_definition->componentList[i].in();
720     }
721     */
722
723   return properties;
724 }