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