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