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