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