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