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