Salome HOME
Union of validator and filter functionalities.
[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 /*!
52  * Get module name from plugins.xml
53  * (property "module")
54  */
55 std::string Config_ModuleReader::getModuleName()
56 {
57   xmlNodePtr aRoot = findRoot();
58   return getProperty(aRoot, PLUGINS_MODULE);
59 }
60
61 void Config_ModuleReader::processNode(xmlNodePtr theNode)
62 {
63   if (isNode(theNode, NODE_PLUGIN, NULL)) {
64     if (!hasRequiredModules(theNode))
65       return;
66     std::string aPluginConf = getProperty(theNode, PLUGIN_CONFIG);
67     std::string aPluginLibrary = getProperty(theNode, PLUGIN_LIBRARY);
68     std::string aPluginScript = getProperty(theNode, PLUGIN_SCRIPT);
69     std::string aPluginName = addPlugin(aPluginLibrary, aPluginScript, aPluginConf);
70
71     std::list<std::string> aFeatures = importPlugin(aPluginName, aPluginConf);
72     std::list<std::string>::iterator it = aFeatures.begin();
73     for (; it != aFeatures.end(); it++) {
74       myFeaturesInFiles[*it] = aPluginConf;
75     }
76   }
77 }
78
79 bool Config_ModuleReader::processChildren(xmlNodePtr theNode)
80 {
81   return isNode(theNode, NODE_PLUGINS, NULL);
82 }
83
84 bool Config_ModuleReader::hasRequiredModules(xmlNodePtr theNode) const
85 {
86   std::string aRequiredModule = normalize(getProperty(theNode, PLUGIN_DEPENDENCY));
87   if(aRequiredModule.empty())
88     return true;
89   std::set<std::string>::iterator it = myDependencyModules.begin();
90   for ( ; it != myDependencyModules.end(); it++ ) {
91     if (*it == aRequiredModule) return true;
92   }
93   return false;
94 }
95
96 std::list<std::string> Config_ModuleReader::importPlugin(const std::string& thePluginLibrary,
97                                                          const std::string& thePluginXmlConf)
98 {
99   if (thePluginXmlConf.empty()) {  //probably a third party library
100     loadLibrary(thePluginLibrary);
101     return std::list<std::string>();
102   }
103
104   Config_FeatureReader aReader = Config_FeatureReader(thePluginXmlConf,
105                                                       thePluginLibrary,
106                                                       myEventGenerated);
107   aReader.readAll();
108   return aReader.features();
109 }
110
111 std::string Config_ModuleReader::addPlugin(const std::string& aPluginLibrary,
112                                            const std::string& aPluginScript,
113                                            const std::string& aPluginConf)
114 {
115   PluginType aType = Config_ModuleReader::Binary;
116   std::string aPluginName;
117   if (!aPluginLibrary.empty()) {
118     aPluginName = aPluginLibrary;
119     if (aPluginConf.empty()) {
120       aType = Config_ModuleReader::Intrenal;
121     }
122   } else if (!aPluginScript.empty()) {
123     aPluginName = aPluginScript;
124     aType = Config_ModuleReader::Python;
125   }
126   if(!aPluginName.empty()) {
127     myPluginTypes[aPluginName] = aType;
128   }
129   addDependencyModule(aPluginName);
130   return aPluginName;
131 }
132
133 void Config_ModuleReader::loadPlugin(const std::string& thePluginName)
134 {
135   PluginType aType = Config_ModuleReader::Binary;
136   if(myPluginTypes.find(thePluginName) != myPluginTypes.end()) {
137     aType = myPluginTypes.at(thePluginName);
138   }
139   switch (aType) {
140     case Config_ModuleReader::Python:
141       loadScript(thePluginName);
142       break;
143     case Config_ModuleReader::Binary:
144     case Config_ModuleReader::Intrenal:
145     default:
146       loadLibrary(thePluginName);
147       break;
148   }
149 }
150
151 void Config_ModuleReader::loadScript(const std::string& theFileName)
152 {
153   /* aquire python thread */
154   PyGILState_STATE gstate = PyGILState_Ensure();
155
156   PyObject* module = PyImport_ImportModule(theFileName.c_str());
157   if (!module) {
158     std::string anErrorMsg = "An error occured while importing " + theFileName;
159     //Get detailed error message:
160     if (PyErr_Occurred()) {
161       PyObject *pstr, *ptype, *pvalue, *ptraceback;
162       PyErr_Fetch(&ptype, &pvalue, &ptraceback);
163       PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
164       pstr = PyObject_Str(pvalue);
165       std::string aPyError = std::string(PyString_AsString(pstr));
166       if (!aPyError.empty()) {
167         anErrorMsg += ":\n" + aPyError;
168       }
169       Py_XDECREF(pstr);
170       Py_XDECREF(ptype);
171       Py_XDECREF(pvalue);
172       Py_XDECREF(ptraceback);
173     }
174     Events_Error::send(anErrorMsg);
175   }
176
177   /* release python thread */
178   PyGILState_Release(gstate);
179 }
180
181 void Config_ModuleReader::loadLibrary(const std::string& theLibName)
182 {
183   std::string aFileName = library(theLibName);
184   if (aFileName.empty())
185     return;
186
187   #ifdef WIN32
188   HINSTANCE aModLib = ::LoadLibrary(aFileName.c_str());
189   #else
190   void* aModLib = dlopen( aFileName.c_str(), RTLD_LAZY | RTLD_GLOBAL );
191   #endif
192   if(!aModLib && theLibName != "DFBrowser") { // don't show error for internal debugging tool
193     std::string anErrorMsg = "Failed to load " + aFileName;
194     #ifdef WIN32
195     DWORD   dwLastError = ::GetLastError();
196     LPSTR messageBuffer = NULL;
197     size_t size = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
198                                  FORMAT_MESSAGE_FROM_SYSTEM | 
199                                  FORMAT_MESSAGE_IGNORE_INSERTS,
200                                  NULL, 
201                                  dwLastError, 
202                                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
203                                  (LPSTR)&messageBuffer, 0, NULL);
204     anErrorMsg += ": " +  std::string(messageBuffer, size);
205     #else
206     anErrorMsg += ": " + std::string(dlerror());
207     #endif
208     std::cerr << anErrorMsg << std::endl;
209     Events_Error::send(anErrorMsg);
210   }
211 }
212
213 void Config_ModuleReader::addDependencyModule(const std::string& theModuleName)
214 {
215   myDependencyModules.insert(normalize(theModuleName));
216 }
217