Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom.git into Dev_1.1.0
[modules/shaper.git] / src / Config / Config_ModuleReader.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 /*
4  * Config_ModuleReader.cpp
5  *
6  *  Created on: Mar 20, 2014
7  *      Author: sbh
8  */
9
10 #include <Config_Keywords.h>
11 #include <Config_Common.h>
12 #include <Config_ModuleReader.h>
13 #include <Config_FeatureReader.h>
14 #include <Events_Error.h>
15
16 #include <libxml/parser.h>
17 #include <libxml/tree.h>
18
19 // Have to be included before std headers
20 #include <Python.h>
21
22 //Necessary for cerr
23 #include <iostream>
24 #include <algorithm>
25
26 #ifdef WIN32
27 #include <windows.h>
28 #pragma warning(disable : 4996) // for getenv
29 #else
30 #include <dlfcn.h>
31 #endif
32
33 std::map<std::string, Config_ModuleReader::PluginType> Config_ModuleReader::myPluginTypes;
34 std::set<std::string> Config_ModuleReader::myDependencyModules;
35
36 Config_ModuleReader::Config_ModuleReader(const char* theEventGenerated)
37     : Config_XMLReader(PLUGIN_FILE),
38       myEventGenerated(theEventGenerated)
39 {
40 }
41
42 Config_ModuleReader::~Config_ModuleReader()
43 {
44 }
45
46 const std::map<std::string, std::string>& Config_ModuleReader::featuresInFiles() const
47 {
48   return myFeaturesInFiles;
49 }
50
51 const std::set<std::string>& Config_ModuleReader::modulePluginFiles() const
52 {
53   return myPluginFiles;
54 }
55
56 /*!
57  * Get module name from plugins.xml
58  * (property "module")
59  */
60 std::string Config_ModuleReader::getModuleName()
61 {
62   xmlNodePtr aRoot = findRoot();
63   return getProperty(aRoot, PLUGINS_MODULE);
64 }
65
66 void Config_ModuleReader::processNode(xmlNodePtr theNode)
67 {
68   if (isNode(theNode, NODE_PLUGIN, NULL)) {
69     if (!hasRequiredModules(theNode))
70       return;
71     std::string aPluginConf = getProperty(theNode, PLUGIN_CONFIG);
72     if (!aPluginConf.empty()) myPluginFiles.insert(aPluginConf);
73     std::string aPluginLibrary = getProperty(theNode, PLUGIN_LIBRARY);
74     std::string aPluginScript = getProperty(theNode, PLUGIN_SCRIPT);
75     std::string aPluginName = addPlugin(aPluginLibrary, aPluginScript, aPluginConf);
76
77     std::list<std::string> aFeatures = importPlugin(aPluginName, aPluginConf);
78     std::list<std::string>::iterator it = aFeatures.begin();
79     for (; it != aFeatures.end(); it++) {
80       myFeaturesInFiles[*it] = aPluginConf;
81     }
82   }
83 }
84
85 bool Config_ModuleReader::processChildren(xmlNodePtr theNode)
86 {
87   return isNode(theNode, NODE_PLUGINS, NULL);
88 }
89
90 bool Config_ModuleReader::hasRequiredModules(xmlNodePtr theNode) const
91 {
92   std::string aRequiredModule = normalize(getProperty(theNode, PLUGIN_DEPENDENCY));
93   if(aRequiredModule.empty())
94     return true;
95   std::set<std::string>::iterator it = myDependencyModules.begin();
96   for ( ; it != myDependencyModules.end(); it++ ) {
97     if (*it == aRequiredModule) return true;
98   }
99   return false;
100 }
101
102 std::list<std::string> Config_ModuleReader::importPlugin(const std::string& thePluginLibrary,
103                                                          const std::string& thePluginXmlConf)
104 {
105   if (thePluginXmlConf.empty()) {  //probably a third party library
106     loadLibrary(thePluginLibrary);
107     return std::list<std::string>();
108   }
109
110   Config_FeatureReader aReader = Config_FeatureReader(thePluginXmlConf,
111                                                       thePluginLibrary,
112                                                       myEventGenerated);
113   aReader.readAll();
114   return aReader.features();
115 }
116
117 std::string Config_ModuleReader::addPlugin(const std::string& aPluginLibrary,
118                                            const std::string& aPluginScript,
119                                            const std::string& aPluginConf)
120 {
121   PluginType aType = Config_ModuleReader::Binary;
122   std::string aPluginName;
123   if (!aPluginLibrary.empty()) {
124     aPluginName = aPluginLibrary;
125     if (aPluginConf.empty()) {
126       aType = Config_ModuleReader::Intrenal;
127     }
128   } else if (!aPluginScript.empty()) {
129     aPluginName = aPluginScript;
130     aType = Config_ModuleReader::Python;
131   }
132   if(!aPluginName.empty()) {
133     myPluginTypes[aPluginName] = aType;
134   }
135   addDependencyModule(aPluginName);
136   return aPluginName;
137 }
138
139 void Config_ModuleReader::loadPlugin(const std::string& thePluginName)
140 {
141   PluginType aType = Config_ModuleReader::Binary;
142   if(myPluginTypes.find(thePluginName) != myPluginTypes.end()) {
143     aType = myPluginTypes.at(thePluginName);
144   }
145   switch (aType) {
146     case Config_ModuleReader::Python:
147       loadScript(thePluginName);
148       break;
149     case Config_ModuleReader::Binary:
150     case Config_ModuleReader::Intrenal:
151     default:
152       loadLibrary(thePluginName);
153       break;
154   }
155 }
156
157 void Config_ModuleReader::loadScript(const std::string& theFileName)
158 {
159   /* aquire python thread */
160   PyGILState_STATE gstate = PyGILState_Ensure();
161
162   PyObject* module = PyImport_ImportModule(theFileName.c_str());
163   if (!module) {
164     std::string anErrorMsg = "An error occured while importing " + theFileName;
165     //Get detailed error message:
166     if (PyErr_Occurred()) {
167       PyObject *pstr, *ptype, *pvalue, *ptraceback;
168       PyErr_Fetch(&ptype, &pvalue, &ptraceback);
169       PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
170       pstr = PyObject_Str(pvalue);
171       std::string aPyError = std::string(PyString_AsString(pstr));
172       if (!aPyError.empty()) {
173         anErrorMsg += ":\n" + aPyError;
174       }
175       Py_XDECREF(pstr);
176       Py_XDECREF(ptype);
177       Py_XDECREF(pvalue);
178       Py_XDECREF(ptraceback);
179     }
180     Events_Error::send(anErrorMsg);
181   }
182
183   /* release python thread */
184   PyGILState_Release(gstate);
185 }
186
187 void Config_ModuleReader::loadLibrary(const std::string& theLibName)
188 {
189   std::string aFileName = library(theLibName);
190   if (aFileName.empty())
191     return;
192
193   #ifdef WIN32
194   HINSTANCE aModLib = ::LoadLibrary(aFileName.c_str());
195   #else
196   void* aModLib = dlopen( aFileName.c_str(), RTLD_LAZY | RTLD_GLOBAL );
197   #endif
198   if(!aModLib && theLibName != "DFBrowser") { // don't show error for internal debugging tool
199     std::string anErrorMsg = "Failed to load " + aFileName;
200     #ifdef WIN32
201     DWORD   dwLastError = ::GetLastError();
202     LPSTR messageBuffer = NULL;
203     size_t size = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
204                                  FORMAT_MESSAGE_FROM_SYSTEM | 
205                                  FORMAT_MESSAGE_IGNORE_INSERTS,
206                                  NULL, 
207                                  dwLastError, 
208                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
209                                  (LPSTR)&messageBuffer, 0, NULL);
210     anErrorMsg += ": " +  std::string(messageBuffer, size);
211     #else
212     anErrorMsg += ": " + std::string(dlerror());
213     #endif
214     std::cerr << anErrorMsg << std::endl;
215     Events_Error::send(anErrorMsg);
216   }
217 }
218
219 void Config_ModuleReader::addDependencyModule(const std::string& theModuleName)
220 {
221   myDependencyModules.insert(normalize(theModuleName));
222 }
223