Package omero :: Module config
[hide private]
[frames] | no frames]

Source Code for Module omero.config

  1  #!/usr/bin/env python 
  2  # encoding: utf-8 
  3  """ 
  4  :: 
  5   
  6     Copyright 2010 Glencoe Software, Inc. All rights reserved. 
  7     Use is subject to license terms supplied in LICENSE.txt 
  8   
  9  """ 
 10   
 11  """ 
 12  Module which parses an icegrid XML file for configuration settings. 
 13   
 14  see ticket:800 
 15  see ticket:2213 - Replacing Java Preferences API 
 16  """ 
 17   
 18  import re 
 19  import os 
 20  import path 
 21  import time 
 22  import logging 
 23  import exceptions 
 24  import portalocker 
 25   
 26  import xml.dom.minidom 
 27   
 28  try: 
 29      from xml.etree.ElementTree import XML, Element, SubElement, Comment, ElementTree, tostring 
 30  except ImportError: 
 31      from elementtree.ElementTree import XML, Element, SubElement, Comment, ElementTree, tostring 
 32   
 33   
34 -class ConfigXml(object):
35 """ 36 37 """ 38 KEY = "omero.config.version" 39 VERSION = "4.2.1" 40 INTERNAL = "__ACTIVE__" 41 DEFAULT = "omero.config.profile" 42 IGNORE = (KEY, DEFAULT) 43
44 - def __init__(self, filename, env_config = None, exclusive = True):
45 self.logger = logging.getLogger(self.__class__.__name__) #: Logs to the class name 46 self.XML = None #: Parsed XML Element 47 self.env_config = env_config #: Environment override 48 self.filename = filename #: Path to the file to be read and written 49 self.source = open(filename, "a+") #: Open file handle 50 self.lock = open("%s.lock" % filename, "a+") #: Open file handle for lock 51 self.exclusive = exclusive #: Whether or not an exclusive lock should be acquired 52 if exclusive: 53 try: 54 portalocker.lock(self.lock, portalocker.LOCK_NB|portalocker.LOCK_EX) 55 except portalocker.LockException, le: 56 self.close() 57 raise 58 59 self.source.seek(0) 60 text = self.source.read() 61 62 if text: 63 self.XML = XML(text) 64 try: 65 self.version_check() 66 except: 67 self.close() 68 raise 69 70 # Nothing defined, so create a new tree 71 if not self.XML: 72 default = self.default() 73 self.XML = Element("icegrid") 74 properties = SubElement(self.XML, "properties", id=self.INTERNAL) 75 _ = SubElement(properties, "property", name=self.DEFAULT, value=default) 76 _ = SubElement(properties, "property", name=self.KEY, value=self.VERSION) 77 properties = SubElement(self.XML, "properties", id=default) 78 _ = SubElement(properties, "property", name=self.KEY, value=self.VERSION)
79
80 - def version(self, id = None):
81 if id is None: 82 id = self.default() 83 properties = self.properties(id) 84 if properties: 85 for x in properties.getchildren(): 86 if x.get("name") == self.KEY: 87 return x.get("value")
88
89 - def version_check(self):
90 for k, v in self.properties(None, True): 91 version = self.version(k) 92 if version != self.VERSION: 93 self.version_fix(v, version)
94
95 - def version_fix(self, props, version):
96 """ 97 Currently we are assuming that all blocks without a 4.2.0 version 98 are bogus. The configuration script when it generates an initial 99 config.xml will use prefs.class to parse the existing values and 100 immediately do the upgrade. 101 """ 102 if version == "4.2.0": 103 # http://trac.openmicroscopy.org.uk/omero/ticket/2613 104 # Remove any reference to the ${omero.dollar} workaround 105 # then map anything of the form: ${...} to @{...} 106 if props: 107 for x in props.getchildren(): 108 if x.get("name", "").startswith("omero.ldap"): 109 orig = x.get("value", "") 110 val = orig.replace("${omero.dollar}", "") 111 val = val.replace("${", "@{") 112 x.set("value", val) 113 self.logger.info("Upgraded 4.2.0 property: %s => %s", orig, val) 114 else: 115 raise exceptions.Exception("Version mismatch: %s has %s" % (props.get("id"), version))
116
117 - def internal(self):
118 return self.properties(self.INTERNAL)
119
120 - def properties(self, id = None, filter_internal = False):
121 122 if not self.XML: 123 return None 124 125 props = self.XML.findall("./properties") 126 if id is None: 127 rv = list() 128 for x in props: 129 id = x.attrib["id"] 130 if filter_internal: 131 if id == self.INTERNAL: 132 continue 133 rv.append((id, x)) 134 return rv 135 for p in props: 136 if "id" in p.attrib and p.attrib["id"] == id: 137 return p
138
139 - def remove(self, id = None):
140 if id is None: 141 id = self.default() 142 properties = self.properties(id) 143 if not properties: 144 raise KeyError("No such configuration: %s" % id) 145 self.XML.remove(properties)
146
147 - def default(self, value = None):
148 if value: 149 self.env_config = value 150 if self.env_config: 151 return self.env_config 152 elif "OMERO_CONFIG" in os.environ: 153 return os.environ["OMERO_CONFIG"] 154 else: 155 # Previously we were calling here: 156 # props = self.props_to_dict(self.internal()) 157 # return props.get(self.DEFAULT, "default") 158 # but we don't want to take the previous default 159 # because then a user would have to explicitly 160 # set: "OMERO_CONFIG=default" 161 return "default"
162
163 - def dump(self):
164 prop_list = self.properties() 165 for id, p in prop_list: 166 props = self.props_to_dict(p) 167 print "# ===> %s <===" % id 168 print self.dict_to_text(props)
169
170 - def save(self):
171 """ 172 Creates a fresh <icegrid> block (removing any unwanted 173 intra-element whitespace) and overwrites the file on disk. 174 """ 175 icegrid = Element("icegrid") 176 comment = Comment("\n".join(["\n", 177 "\tThis file was generated at %s by the OmeroConfig system.", 178 "\tDo not edit directly but see bin/omero config for details.", 179 "\tThis file may be included into your IceGrid application.", 180 "\n"]) % time.ctime()) 181 icegrid.append(comment) 182 # First step is to add a new self.INTERNAL block to it 183 # which has self.DEFAULT set to the current default, 184 # and then copies all the values from that profile. 185 default = self.default() 186 internal = SubElement(icegrid, "properties", id=self.INTERNAL) 187 SubElement(internal, "property", name=self.DEFAULT, value=default) 188 SubElement(internal, "property", name=self.KEY, value=self.VERSION) 189 to_copy = self.properties(default) 190 if to_copy is not None: 191 for x in to_copy.getchildren(): 192 if x.get("name") != self.DEFAULT and x.get("name") != self.KEY: 193 SubElement(internal, "property", x.attrib) 194 else: 195 # Doesn't exist, create it 196 properties = SubElement(icegrid, "properties", id=default) 197 SubElement(properties, "property", name=self.KEY, value=self.VERSION) 198 # Now we simply reproduce all the other blocks 199 prop_list = self.properties(None, True) 200 for k, p in prop_list: 201 self.clear_text(p) 202 icegrid.append(p) 203 self.source.seek(0) 204 self.source.truncate() 205 self.source.write(self.element_to_xml(icegrid)) 206 self.source.flush()
207
208 - def close(self):
209 try: 210 # If we didn't get an XML instance, 211 # then something has gone wrong and 212 # we should exit. 213 if self.XML: 214 self.save() 215 finally: 216 try: 217 self.source.close() 218 finally: 219 self.lock.close()
220
221 - def props_to_dict(self, c):
222 223 if c is None: 224 return {} 225 226 rv = dict() 227 props = c.findall("./property") 228 for p in props: 229 if "name" in p.attrib: 230 rv[p.attrib["name"]] = p.attrib.get("value", "") 231 return rv
232
233 - def dict_to_text(self, parsed = None):
234 235 if parsed is None: 236 return 237 238 rv = "" 239 for k, v in parsed.items(): 240 rv += "%s=%s" % (k, v) 241 return rv
242
243 - def element_to_xml(self, elem):
244 string = tostring(elem, 'utf-8') 245 return xml.dom.minidom.parseString(string).toprettyxml(" ", "\n", None)
246
247 - def clear_text(self, p):
248 """ 249 To prevent the accumulation of text outside of elements (including whitespace) 250 we walk the given element and remove tail from it and it's children. 251 """ 252 p.tail = "" 253 p.text = "" 254 for p2 in p.getchildren(): 255 self.clear_text(p2)
256 257 # 258 # Map interface on the default properties element 259 #
260 - def as_map(self):
261 return self.props_to_dict(self.properties(self.default()))
262
263 - def keys(self):
264 return self.as_map().keys()
265
266 - def __getitem__(self, key):
267 return self.props_to_dict(self.properties(self.default()))[key]
268
269 - def __setitem__(self, key, value):
270 default = self.default() 271 props = self.properties(default) 272 273 if props == None: 274 props = SubElement(self.XML, "properties", {"id":default}) 275 276 for x in props.findall("./property"): 277 if x.attrib["name"] == key: 278 x.attrib["value"] = value 279 return 280 SubElement(props, "property", {"name":key, "value":value})
281
282 - def __delitem__(self, key):
283 default = self.default() 284 props = self.properties(default) 285 to_remove = [] 286 for p in props.getchildren(): 287 if p.get("name") == key: 288 to_remove.append(p) 289 for x in to_remove: 290 props.remove(x)
291