Salome HOME
First test qui HPsalome container is running.
[modules/yacs.git] / src / runtime / CppContainer.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 #include <iostream>
21 #include <sstream>
22 #ifdef WIN32
23 #include <windows.h>
24 #define dlopen LoadLibrary
25 #define dlclose FreeLibrary
26 #define dlsym GetProcAddress
27 #else
28 #include <dlfcn.h>
29 #endif
30
31 #include "CppContainer.hxx"
32 #include "CppComponent.hxx"
33 #include "Exception.hxx"
34 #include <algorithm>
35 #include <iostream>
36
37
38 using namespace YACS::ENGINE;
39
40 //#define _DEVDEBUG_
41 #include "YacsTrace.hxx"
42
43 //=============================================================================
44 /*! 
45  *  Local C++ container class constructor
46  */
47 //=============================================================================
48
49 CppContainer::CppContainer() : _trueCont(0L)
50 {
51     DEBTRACE("CppContainer::CppContainer()");
52 }
53
54
55 //=============================================================================
56 /*! 
57  *  Local C++ container class destructor
58  */
59 //=============================================================================
60
61 CppContainer::~CppContainer()
62 {
63     DEBTRACE("CppContainer::~CppContainer()");
64 }
65
66 void CppContainer::lock()
67 {
68   _mutex.lock();
69 }
70
71 void CppContainer::unLock()
72 {
73   _mutex.unLock();
74 }
75
76 bool CppContainer::isAlreadyStarted(const Task *askingNode) const
77 {
78   return NULL != _trueCont;
79 }
80
81 void CppContainer::start(const Task *askingNode) throw (YACS::Exception)
82 {
83   _trueCont = LocalContainer::get();
84 }
85
86 void CppContainer::shutdown(int level)
87 {
88
89 }
90
91 Container *CppContainer::clone() const
92 {
93   if(_isAttachedOnCloning)
94     {
95       incrRef();
96       return (Container*) (this);
97     }
98   else
99     return new CppContainer(*this);
100 }
101
102 Container *CppContainer::cloneAlways() const
103 {
104   return new CppContainer(*this);
105 }
106
107 bool CppContainer::loadComponentLibrary(const std::string & componentName) throw (YACS::Exception)
108     {
109   if (_trueCont)
110     {
111       LocalLibrary L = _trueCont->loadComponentLibrary(componentName);
112       return L.good();
113     }
114   else
115     {
116       std::string mesg = "CppContainer not started";
117       throw YACS::Exception(mesg);
118     }
119   return false;
120     }
121
122 CppComponent * CppContainer::createComponentInstance(const std::string & componentName, int /* studyID */)
123 {
124   DEBTRACE("CppContainer::createComponentInstance");
125   if (_trueCont)
126     return _trueCont->createComponentInstance(componentName.c_str());
127   else
128     {
129       std::string mesg = "CppContainer not started";
130       throw YACS::Exception(mesg);
131     }
132 }
133
134 void CppContainer::createInternalInstance(const std::string & name, void *&obj, 
135                                           RunFunction &r, TerminateFunction &t)
136 {
137   DEBTRACE("CppContainer::createInternalInstance");
138   if (_trueCont)
139     _trueCont->createInternalInstance(name.c_str(), obj, r, t);
140   else
141     {
142       std::string mesg = "CppContainer not started";
143       throw YACS::Exception(mesg);
144     }
145 }
146
147 void CppContainer::unregisterComponentInstance(CppComponent *compo)
148 {
149   if (_trueCont)
150     _trueCont->unregisterComponentInstance(compo);
151 }
152
153
154 std::string CppContainer::getPlacementId(const Task *askingNode) const
155 {
156   return "/";
157 }
158
159 std::string CppContainer::getFullPlacementId(const Task *askingNode) const
160 {
161   return "/";
162 }
163
164 void CppContainer::checkCapabilityToDealWith(const ComponentInstance *inst) const throw(YACS::Exception)
165 {
166   if(inst->getKind()!=CppComponent::KIND)
167     throw Exception("CppContainer::checkCapabilityToDealWith : CppContainer is not able to deal with this type of ComponentInstance.");
168 }
169
170 std::map<std::string, LocalLibrary> LocalContainer::_library_map; // libraries, loaded
171 std::multimap<std::string, CppComponent *> LocalContainer::_instance_map;
172
173 LocalContainer * LocalContainer::_singleton = NULL;
174
175 LocalContainer::LocalContainer()
176 {
177 }
178
179 LocalContainer::~LocalContainer()
180 {
181     destroy();
182 }
183
184 LocalContainer * LocalContainer::get()
185 {
186     if (NULL == _singleton) 
187     {
188         _singleton = new LocalContainer;
189     }
190     return _singleton;
191 }
192
193 void LocalContainer::destroy()
194 {
195   if (NULL == _singleton)
196     return;
197
198   // destroy all component instances
199   _instance_mapMutex.lock(); // lock
200   std::multimap<std::string, CppComponent *>::iterator iI, iJ;
201   for (iI=_instance_map.begin(); iI != _instance_map.end(); iI = iJ)
202     {
203       iJ = iI++;
204       iI->second->setContainer(NULL);
205       delete iI->second;
206     }
207   _instance_map.clear();
208   _instance_mapMutex.unLock(); // unlock
209
210   // unload all dynamic libraries
211   _library_mapMutex.lock();
212   std::map<std::string, LocalLibrary>::iterator iL;
213   for (iL=_library_map.begin(); iL != _library_map.end(); iL++)
214     dlclose(iL->second.handle);
215   _library_map.clear();
216   _library_mapMutex.unLock();
217
218   delete _singleton;
219   _singleton = NULL;
220 }
221
222
223 //=============================================================================
224 //! Find or create a new C++ component instance
225 /*! 
226  *  Create a new component class (C++ implementation)
227  *  \param name : component name
228  *
229  *  Try to return a handle to an new instance of a C++ component
230  *  If the associated library is not loaded, try to load it
231  *  
232  * \return a handle to the component instance or throw an exception
233  *  if it's not possible
234  */
235 //=============================================================================
236 CppComponent * LocalContainer::createComponentInstance(const char * name)
237 {
238   void *o;
239   RunFunction r;
240   TerminateFunction t;
241   
242   createInternalInstance(name, o, r, t);
243   
244   CppComponent * C;
245   C = new CppComponent(o, r, t, name);
246   _instance_mapMutex.lock(); // lock to be alone 
247   _instance_map.insert(std::pair<std::string, CppComponent *>(name, C));
248   _instance_mapMutex.unLock(); // unlock
249   return C;
250 }
251
252 void LocalContainer::createInternalInstance(const char *name, void *&obj, 
253                                             RunFunction &r, TerminateFunction &t)
254 {
255   LocalLibrary L;
256
257   std::map<std::string, LocalLibrary>::iterator foundL = _library_map.find(name);
258   if (foundL != _library_map.end())
259     L = foundL->second;
260   else
261     L = loadComponentLibrary(name, NULL, false);
262   
263   r = L.runHandle;
264   InitFunction i = L.initHandle;
265   t = L.terminateHandle;
266   
267   PingFunction p = L.pingHandle;
268   if (p) p();
269   
270   obj = i();
271   
272 }
273
274 void LocalContainer::unregisterComponentInstance(CppComponent * C)
275 {
276   _instance_mapMutex.lock(); // lock to be alone
277   _instance_map.erase(C->getCompoName());
278   _instance_mapMutex.unLock(); // unlock
279 }
280
281 inline void toupper (std::string & s)
282 {
283   transform (s.begin (), s.end (), s.begin (), (int(*)(int)) toupper);
284 }
285
286 LocalLibrary  LocalContainer::loadComponentLibrary(const std::string & aCompName, const char * prefix, bool forcedLoad)
287 {
288
289   // if forcedLoad is true, unload library if it exists
290   // if forcedLoad is false, return the existing library or load it
291   
292   if (forcedLoad)
293       unLoadComponentLibrary(aCompName);
294   else 
295     {
296       std::map<std::string, LocalLibrary >::iterator itLib 
297            = _library_map.find(aCompName);
298       if (itLib !=  _library_map.end()) return itLib->second;
299     }
300     
301   // --- try dlopen C++ component
302
303   std::string sprefix;
304   if (prefix)
305     sprefix = prefix;
306   else 
307     {
308       std::string s = aCompName + "_ROOT_DIR";
309       toupper(s);
310       const char * t = getenv(s.c_str());
311       sprefix="";
312       if (t) 
313         {
314           sprefix = t;
315           sprefix += "/lib/salome";
316         }
317     }
318   
319 #ifndef WIN32
320   std::string impl_name = std::string ("lib") + aCompName + std::string("Local.so");
321   if(sprefix != "")
322     impl_name = sprefix + std::string("/") + impl_name;
323 #else
324   std::string impl_name = aCompName + std::string("Local.dll");
325   impl_name = sprefix + std::string("\\") + impl_name;
326 #endif
327   DEBTRACE("impl_name = " << impl_name);
328     
329 #if defined( WIN32 )
330   HMODULE handle;
331   handle = dlopen( impl_name.c_str() ) ;
332 #else
333   void* handle;
334   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
335 #endif
336
337   const char * sError;
338 #if defined( WIN32 )
339   sError = "Not available here !";
340 #endif
341   
342 #if defined( WIN32 )
343   if (!handle) 
344 #else
345   sError = dlerror();
346   if ((sError = dlerror()) || !handle) 
347 #endif
348     {
349       std::stringstream msg;
350       msg << "Can't load shared library : " << impl_name
351           << " (dlopen error : " << sError << ") at "
352           << __FILE__ << ":" << __LINE__;
353       throw YACS::Exception(msg.str());
354     }
355   
356   void *ihandle, *rhandle, *phandle = NULL, *thandle = NULL;
357       
358   ihandle = dlsym(handle, "__init");
359 #if defined( WIN32 )
360   if (!ihandle)
361 #else
362   if (sError = dlerror()) 
363 #endif
364     {
365       dlclose(handle);
366       std::stringstream msg;
367       msg << "Library " << impl_name
368           << " doesn't contains initialization function (" << sError << ") at "
369           << __FILE__ << ":" << __LINE__;
370       throw YACS::Exception(msg.str());
371     }
372   
373   rhandle = dlsym(handle, "__run");
374 #if defined( WIN32 )
375   if (!rhandle)
376 #else
377   if (sError = dlerror()) 
378 #endif
379     {
380       dlclose(handle);
381       std::stringstream msg;
382       msg << "Library " << impl_name
383           << " doesn't contains main switch function (" << sError << ") at "
384           << __FILE__ << ":" << __LINE__;
385       throw YACS::Exception(msg.str());
386     }
387       
388   thandle = dlsym(handle, "__terminate");
389 #if defined( WIN32 )
390   if (!thandle)
391 #else
392   if (sError = dlerror()) 
393 #endif
394     {
395       dlclose(handle);
396       std::stringstream msg;
397       msg << "Library " << impl_name
398           << " doesn't contains terminate function (" << sError << ") at "
399           << __FILE__ << ":" << __LINE__;
400       throw YACS::Exception(msg.str());
401     }
402   phandle = dlsym(handle, "__ping");
403       
404   _library_map[aCompName] = LocalLibrary(handle, (InitFunction) ihandle, 
405                                                  (RunFunction)  rhandle, 
406                                                  (PingFunction) phandle,
407                                                  (TerminateFunction) thandle);
408   return _library_map[aCompName];
409 }
410
411 void LocalContainer::unLoadComponentLibrary(const std::string & aCompName)
412 {
413   std::map<std::string, LocalLibrary >::iterator itLib 
414            = _library_map.find(aCompName);
415   
416   if (itLib ==  _library_map.end()) return;
417   
418   dlclose(itLib->second.handle);
419   _library_map.erase(itLib);
420
421 }