1 // Copyright (C) 2014-2017 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
21 * Config_ModuleReader.cpp
23 * Created on: Mar 20, 2014
29 #include <Config_Keywords.h>
30 #include <Config_Common.h>
31 #include <Config_ModuleReader.h>
32 #include <Config_FeatureReader.h>
33 #include <Events_InfoMessage.h>
35 #include <libxml/parser.h>
36 #include <libxml/tree.h>
38 // Have to be included before std headers
47 #pragma warning(disable : 4996) // for getenv
52 std::map<std::string, Config_ModuleReader::PluginType> Config_ModuleReader::myPluginTypes;
53 std::set<std::string> Config_ModuleReader::myDependencyModules;
55 Config_ModuleReader::Config_ModuleReader(const char* theEventGenerated)
56 : Config_XMLReader(PLUGIN_FILE),
57 myEventGenerated(theEventGenerated)
61 Config_ModuleReader::~Config_ModuleReader()
65 const std::map<std::string, std::string>& Config_ModuleReader::featuresInFiles() const
67 return myFeaturesInFiles;
70 const std::set<std::string>& Config_ModuleReader::modulePluginFiles() const
76 * Get module name from plugins.xml
79 std::string Config_ModuleReader::getModuleName()
81 xmlNodePtr aRoot = findRoot();
82 return getProperty(aRoot, PLUGINS_MODULE);
86 void Config_ModuleReader::addFeature(const std::string& theFeatureName,
87 const std::string& thePluginConfig)
89 if (myFeaturesInFiles.count(theFeatureName)) {
90 std::string anErrorMsg = "Can not register feature '%1' in plugin '%2'."
91 " There is a feature with the same ID.";
92 Events_InfoMessage("Config_ModuleReader", anErrorMsg)
93 .arg(theFeatureName).arg(thePluginConfig).send();
97 myFeaturesInFiles[theFeatureName] = thePluginConfig;
100 void Config_ModuleReader::processNode(xmlNodePtr theNode)
102 if (isNode(theNode, NODE_PLUGIN, NULL)) {
103 if (!hasRequiredModules(theNode))
105 std::string aPluginConf = getProperty(theNode, PLUGIN_CONFIG);
106 if (!aPluginConf.empty())
107 myPluginFiles.insert(aPluginConf);
108 std::string aPluginLibrary = getProperty(theNode, PLUGIN_LIBRARY);
109 std::string aPluginScript = getProperty(theNode, PLUGIN_SCRIPT);
110 std::string aPluginName = addPlugin(aPluginLibrary, aPluginScript, aPluginConf);
112 std::list<std::string> aFeatures = importPlugin(aPluginName, aPluginConf);
113 std::list<std::string>::iterator it = aFeatures.begin();
114 for (; it != aFeatures.end(); it++) {
115 addFeature(*it, aPluginConf);
120 bool Config_ModuleReader::processChildren(xmlNodePtr theNode)
122 return isNode(theNode, NODE_PLUGINS, NULL);
125 bool Config_ModuleReader::hasRequiredModules(xmlNodePtr theNode) const
127 std::string aRequiredModule = normalize(getProperty(theNode, PLUGIN_DEPENDENCY));
128 if(aRequiredModule.empty())
130 std::set<std::string>::iterator it = myDependencyModules.begin();
131 for ( ; it != myDependencyModules.end(); it++ ) {
132 if (*it == aRequiredModule) return true;
137 std::list<std::string> Config_ModuleReader::importPlugin(const std::string& thePluginLibrary,
138 const std::string& thePluginXmlConf)
140 if (thePluginXmlConf.empty()) { //probably a third party library
141 loadLibrary(thePluginLibrary);
142 return std::list<std::string>();
145 Config_FeatureReader aReader = Config_FeatureReader(thePluginXmlConf,
149 return aReader.features();
152 std::string Config_ModuleReader::addPlugin(const std::string& aPluginLibrary,
153 const std::string& aPluginScript,
154 const std::string& aPluginConf)
156 PluginType aType = Config_ModuleReader::Binary;
157 std::string aPluginName;
158 if (!aPluginLibrary.empty()) {
159 aPluginName = aPluginLibrary;
160 if (aPluginConf.empty()) {
161 aType = Config_ModuleReader::Intrenal;
163 } else if (!aPluginScript.empty()) {
164 aPluginName = aPluginScript;
165 aType = Config_ModuleReader::Python;
167 if(!aPluginName.empty()) {
168 myPluginTypes[aPluginName] = aType;
170 addDependencyModule(aPluginName);
174 void Config_ModuleReader::loadPlugin(const std::string& thePluginName)
176 PluginType aType = Config_ModuleReader::Binary;
177 if(myPluginTypes.find(thePluginName) != myPluginTypes.end()) {
178 aType = myPluginTypes.at(thePluginName);
181 case Config_ModuleReader::Python:
182 loadScript(thePluginName);
184 case Config_ModuleReader::Binary:
185 case Config_ModuleReader::Intrenal:
187 loadLibrary(thePluginName);
192 void Config_ModuleReader::loadScript(const std::string& theFileName, bool theSendErr)
194 /* acquire python thread */
195 PyGILState_STATE gstate = PyGILState_Ensure();
197 PyObject* module = PyImport_ImportModule(theFileName.c_str());
199 std::string anErrorMsg = "An error occurred while importing " + theFileName;
200 //Get detailed error message:
201 if (PyErr_Occurred()) {
202 PyObject *pstr, *ptype, *pvalue, *ptraceback;
203 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
204 PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
205 pstr = PyObject_Str(pvalue);
206 std::string aPyError = std::string(PyString_AsString(pstr));
207 if (!aPyError.empty()) {
208 anErrorMsg += ":\n" + aPyError;
213 Py_XDECREF(ptraceback);
216 Events_InfoMessage("Config_ModuleReader", anErrorMsg).send();
219 /* release python thread */
220 PyGILState_Release(gstate);
223 void Config_ModuleReader::loadLibrary(const std::string& theLibName)
225 std::string aFileName = library(theLibName);
226 if (aFileName.empty())
230 HINSTANCE aModLib = ::LoadLibrary(aFileName.c_str());
232 void* aModLib = dlopen( aFileName.c_str(), RTLD_LAZY | RTLD_GLOBAL );
234 if(!aModLib && theLibName != "DFBrowser") { // don't show error for internal debugging tool
235 std::string anErrorMsg = "Failed to load " + aFileName;
237 DWORD dwLastError = ::GetLastError();
238 LPSTR messageBuffer = NULL;
239 size_t size = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
240 FORMAT_MESSAGE_FROM_SYSTEM |
241 FORMAT_MESSAGE_IGNORE_INSERTS,
244 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
245 (LPSTR)&messageBuffer, 0, NULL);
246 anErrorMsg += ": " + std::string(messageBuffer, size);
248 anErrorMsg += ": " + std::string(dlerror());
250 std::cerr << anErrorMsg << std::endl;
251 Events_InfoMessage("Config_ModuleReader", anErrorMsg).send();
255 void Config_ModuleReader::addDependencyModule(const std::string& theModuleName)
257 myDependencyModules.insert(normalize(theModuleName));