Module EDConfiguration
[hide private]
[frames] | no frames]

Source Code for Module EDConfiguration

  1  # coding: utf8 
  2  # 
  3  #    Project: The EDNA Kernel 
  4  #             http://www.edna-site.org 
  5  # 
  6  #    Copyright (C) 2008-2012 European Synchrotron Radiation Facility 
  7  #                            Grenoble, France 
  8  # 
  9  #    Principal authors: Marie-Francoise Incardona (incardon@esrf.fr) 
 10  #                       Olof Svensson (svensson@esrf.fr) 
 11  # 
 12  #    This program is free software: you can redistribute it and/or modify 
 13  #    it under the terms of the GNU Lesser General Public License as published 
 14  #    by the Free Software Foundation, either version 3 of the License, or 
 15  #    (at your option) any later version. 
 16  # 
 17  #    This program is distributed in the hope that it will be useful, 
 18  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 19  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 20  #    GNU Lesser General Public License for more details. 
 21  # 
 22  #    You should have received a copy of the GNU General Public License 
 23  #    and the GNU Lesser General Public License  along with this program. 
 24  #    If not, see <http://www.gnu.org/licenses/>. 
 25  # 
 26  from __future__ import with_statement 
 27   
 28  __authors__ = [ "Marie-Francoise Incardona", "Olof Svensson", "Jérôme Kieffer" ] 
 29  __contact__ = "svensson@esrf.fr" 
 30  __license__ = "LGPLv3+" 
 31  __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" 
 32   
 33  """ 
 34  This class handles the EDNA configuration XML/JSON files. 
 35  """ 
 36   
 37  import os, json 
 38  from EDVerbose import EDVerbose 
 39  from EDLogging import EDLogging 
 40  from EDUtilsFile import EDUtilsFile 
 41  from EDUtilsPath import EDUtilsPath 
 42  from EDFactoryPluginStatic import EDFactoryPluginStatic 
 43  from EDDecorator import deprecated 
 44  from XSDataCommon import XSConfiguration, XSPluginItem, XSParamList, XSParamItem 
45 46 -def bestType(a):
47 """ 48 convert a string to it's typed version 49 """ 50 if a.lower() in ["true", "on"]: 51 return True 52 if a.lower() in ["false", "off"]: 53 return False 54 if a.lower() in ["none", "nul", "null"]: 55 return None 56 try: 57 ia = int(a) 58 except: 59 ia = None 60 try: 61 fa = float(a) 62 except: 63 fa = None 64 if ia is not None and fa is not None: 65 if ia == fa: 66 return ia 67 else: 68 return fa 69 else: 70 return str(a)
71
72 73 -class EDConfiguration(EDLogging):
74 """ 75 This class handles the EDNA configuration XML files. The structure of 76 the XML is described in the XSDataCommon data model. 77 78 If environment variable strings like "$XXX" or "${XXX}" is present in the 79 configuration file, the strings are replaced with the corresponding 80 environment variable content. For example, if "${CCP4} is present in the 81 XML string, the string "${CCP4}" is replaced by the environment variable $CCP4 82 content. 83 """ 84 85
86 - def __init__(self, _strFileName=None):
87 """"Set up semaphore for thread safeness and dictionary for config files""" 88 EDLogging.__init__(self) 89 self._dictConfigurationFiles = {} 90 self._dictPluginConfiguration = {} 91 if _strFileName is not None: 92 self.addConfigurationFile(_strFileName)
93
94 - def addConfigurationFile(self, _strFileName, _bReplace=True):
95 """Loads an XML/JSON config file into the dictionary if not already loaded""" 96 strFileName = os.path.abspath(_strFileName) 97 if not os.path.exists(strFileName): 98 self.WARNING("Trying to add configuration file but file %s doesn't exist!" % _strFileName) 99 else: 100 if strFileName in self._dictConfigurationFiles: 101 self.DEBUG("EDConfiguration.addConfigurationFile: File %s already parsed, in cache" % strFileName) 102 else: 103 self.DEBUG("EDConfiguration.addConfigurationFile: Parsing file %s" % strFileName) 104 strConfiguration = EDUtilsFile.readFileAndParseVariables(strFileName) 105 if strFileName.endswith(".xml"): 106 xsConfiguration = XSConfiguration.parseString(strConfiguration) 107 if xsConfiguration is not None : 108 dictConfig = {"__extend__":[]} 109 for other in xsConfiguration.XSImportConfiguration: 110 if other.directory not in [None, "None"]: 111 dictConfig["__extend__"].append(os.path.join(other.directory, other.name)) 112 else: 113 dictConfig["__extend__"].append(other.name) 114 115 xsPluginList = xsConfiguration.getXSPluginList() 116 if xsPluginList is not None: 117 for pluginItem in xsPluginList.getXSPluginItem(): 118 plugin_conf = {} 119 plugin_name = pluginItem.name 120 paramList = pluginItem.getXSParamList() 121 if paramList: 122 for paramItem in paramList.getXSParamItem(): 123 plugin_conf[paramItem.name] = bestType(paramItem.value) 124 dictConfig[plugin_name] = plugin_conf 125 else: #JSON mode 126 dictConfig = json.loads(strConfiguration) 127 # Make sure we are thread safe when manipulating the cache 128 with self.locked(): 129 self._dictConfigurationFiles[strFileName] = dictConfig 130 # First look for configuration imports 131 for importConfiguration in dictConfig["__extend__"]: 132 if importConfiguration.startswith(os.sep): 133 for ext in ["", ".json", ".xml" ]: 134 if os.path.isfile(importConfiguration + ext): 135 strImportPath = importConfiguration + ext 136 break 137 else: 138 for ext in ["", ".json", ".xml" ]: 139 path = os.path.join(os.path.dirname(strFileName), importConfiguration + ext) 140 if os.path.isfile(path): 141 strImportPath = path 142 break 143 self.DEBUG("Importing configuration file : %s" % strImportPath) 144 self.addConfigurationFile(strImportPath, _bReplace) #Was True, why? 145 146 # Make sure we are thread safe when manipulating the cache 147 with self.locked(): 148 # Load configurations into the plugin dictionary 149 for strPluginName in dictConfig: 150 if strPluginName == "__extend__": 151 continue 152 if strPluginName in self._dictPluginConfiguration: 153 if _bReplace: 154 self.DEBUG("EDConfiguration.addConfigurationFile: plugin configuration for %s already exists and will be replaced." % strPluginName) 155 self._dictPluginConfiguration[strPluginName] = dictConfig[strPluginName] 156 else: 157 self.DEBUG("EDConfiguration.addConfigurationFile: plugin configuration for %s already exists and will not be replaced." % strPluginName) 158 else: 159 self.DEBUG("EDConfiguration.addConfigurationFile: adding plugin configuration for %s." % strPluginName) 160 self._dictPluginConfiguration[strPluginName] = dictConfig[strPluginName]
161 162
163 - def getPathToProjectConfigurationFile(self, _strPluginName):
164 """ 165 This method returns the path to the Project configuration file. 166 167 @param _strPluginName: Name of the module 168 @type _strPluginName: python string 169 170 @return: The path to the project configuration file 171 @type: python string 172 """ 173 strPathToProjectConfigurationFile = None 174 strCurrentDirectory = EDFactoryPluginStatic.getModuleLocation(_strPluginName) 175 if strCurrentDirectory is None: 176 self.WARNING("Cannot find path to configuration for plugin %s" % _strPluginName) 177 else: 178 with self.locked(): 179 bConfFileFound = False 180 strPathToProjectConfigurationFile = None 181 strConfigurationFileBaseName = "XSConfiguration_%s" % EDUtilsPath.EDNA_SITE 182 while not bConfFileFound: 183 strPreviousDirectory = strCurrentDirectory 184 strCurrentDirectory = os.path.dirname(strCurrentDirectory) 185 if strCurrentDirectory in (EDUtilsPath.EDNA_HOME, strPreviousDirectory): 186 strPathToProjectConfigurationFile = None 187 break 188 strPathToConfigurationDirectory = os.path.abspath(os.path.join(strCurrentDirectory, "conf")) 189 for ext in [".json", ".xml"]: 190 strPathToProjectConfigurationFile = os.path.abspath(os.path.join(strPathToConfigurationDirectory, \ 191 strConfigurationFileBaseName + ext)) 192 self.DEBUG("Looking for configuration file for %s in %s" % 193 (_strPluginName, strPathToProjectConfigurationFile)) 194 bConfFileFound = os.path.isfile(strPathToProjectConfigurationFile) 195 if bConfFileFound: 196 break 197 return strPathToProjectConfigurationFile
198 199 200 ############################################################################ 201 # Dictionary like interface 202 ############################################################################ 203
204 - def get(self, _strPluginName, default=None):
205 """ 206 Returns the configuration for a given plugin as a dictionary. 207 208 If the plugin configuration is not in the cache the methods 209 'getPathToProjectConfigurationFile' and 'addConfigurationFile' 210 are called for attempting to load the plugin configuration 211 from a file (lazy loading). 212 213 @param _strPluginName: name of the plugin 214 @param default: optional default return value if plugin not loaded (e.g. {}) 215 @return: configuration as a dict (or default value) 216 """ 217 dictPluginConfiguration = default 218 if _strPluginName in self._dictPluginConfiguration: 219 dictPluginConfiguration = self._dictPluginConfiguration[_strPluginName] 220 else: 221 strPathToProjectConfigurationFile = self.getPathToProjectConfigurationFile(_strPluginName) 222 if strPathToProjectConfigurationFile is not None: 223 self.addConfigurationFile(strPathToProjectConfigurationFile, _bReplace=True) 224 if _strPluginName in self._dictPluginConfiguration: 225 dictPluginConfiguration = self._dictPluginConfiguration[_strPluginName] 226 return dictPluginConfiguration
227
228 - def __contains__(self, key):
229 return (key in self._dictPluginConfiguration)
230
231 - def __getitem__(self, _strPluginName):
232 """ 233 edConfig["myPlugin"] -> {} 234 """ 235 return self._dictPluginConfiguration.get(_strPluginName, {})
236
237 - def __setitem__(self, _strPluginName, plugin_config={}):
238 """ 239 edConfig["myPlugin"]= {"timeout":5} 240 241 @param _strPluginName: name of the plugin as a string 242 @param plugin_config: configuration of a whole plugin as a dict 243 """ 244 with self.locked(): 245 self._dictPluginConfiguration[_strPluginName] = plugin_config
246
247 - def __len__(self):
248 return len(self._dictPluginConfiguration)
249
250 - def getPluginListSize(self):
251 """ 252 Returns the number of plugins configured 253 """ 254 return len(self._dictPluginConfiguration)
255 256 ################################################################################ 257 # # Deprecation zone 258 ################################################################################ 259 260 # @deprecated
261 - def getXSConfigurationItem(self, _strPluginName):
262 "Method offering compatibility with XML structure: deprecated !!!" 263 config = None 264 if _strPluginName in self._dictPluginConfiguration: 265 config = self._dictPluginConfiguration[_strPluginName] 266 else: # Try to load "project" configuration 267 config = self.get(_strPluginName) 268 if config is not None: 269 return XSPluginItem(name=_strPluginName, 270 XSParamList=XSParamList([XSParamItem(name=i, value=str(config[i])) for i in config]))
271 272 273 # @deprecated
274 - def setXSConfigurationItem(self, _xsPluginItem):
275 "Compatibility with XML structure: deprecated" 276 if _xsPluginItem is not None: 277 if _xsPluginItem.name is not None: 278 strPluginName = _xsPluginItem.name 279 plugin_conf = {} 280 paramList = _xsPluginItem.getXSParamList() 281 if paramList: 282 for paramItem in paramList.getXSParamItem(): 283 plugin_conf[paramItem.name] = bestType(paramItem.value) 284 if strPluginName in self._dictPluginConfiguration.keys(): 285 self.DEBUG("Replacing configuration for plugin %s" % strPluginName) 286 else: 287 self.DEBUG("Setting configuration for plugin %s" % strPluginName) 288 with self.locked(): 289 self._dictPluginConfiguration[strPluginName] = plugin_conf
290 291
292 - def getStringValue(self, _strPluginName, _strConfigurationName):
293 "Get the configuration for one plugin and one config parameter, as a string" 294 config = None 295 if _strPluginName in self._dictPluginConfiguration: 296 config = self._dictPluginConfiguration[_strPluginName] 297 else: # Try to load "project" configuration 298 config = self.get(_strPluginName) 299 if (config is not None) and (_strConfigurationName in config): 300 return str(config[_strConfigurationName])
301 302 303 304 # @deprecated 305 @staticmethod
306 - def getParamItem(_xsPluginItem, _pyStrParamName):
307 """ 308 Returns the corresponding 'paramItem' for a given plugin name 309 -> Deprecated 310 """ 311 xsParamList = _xsPluginItem.getXSParamList() 312 xsParamItemReturn = None 313 314 if (xsParamList != None): 315 xsParamItems = xsParamList.getXSParamItem() 316 for xsParamItem in xsParamItems: 317 if (xsParamItem.getName() == _pyStrParamName): 318 xsParamItemReturn = xsParamItem 319 break 320 return xsParamItemReturn
321 322 # @deprecated 323 @classmethod
324 - def getStringParamValue(cls, _xsPluginItem, _pyStrParamName):
325 """ 326 Returns the parameter value in a string format 327 -> Deprecated 328 """ 329 strParamValue = None 330 xsParamItem = cls.getParamItem(_xsPluginItem, _pyStrParamName) 331 if xsParamItem is not None: 332 strParamValue = xsParamItem.getValue() 333 return strParamValue
334 335 336 # @deprecated 337 @classmethod
338 - def getIntegerParamValue(cls, _xsPluginItem, _pyStrParamName):
339 """ 340 Returns the parameter value in a integer format 341 -> Deprecated 342 """ 343 strParamValue = cls.getStringParamValue(_xsPluginItem, _pyStrParamName) 344 try: 345 return int(strParamValue) 346 except TypeError: 347 return 348 except ValueError: 349 EDVerbose.ERROR("invalid literal for int(), got %s" % strParamValue)
350