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