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