Package AccessEngine :: Module AESettingsManager'
[hide private]
[frames] | no frames]

Source Code for Module AccessEngine.AESettingsManager'

  1  ''' 
  2  Defines a class responsible for managing the saving and loading of settings 
  3  from disk. 
  4   
  5  @var PROFILES_PATH: Path to all persisted setting for user profiles 
  6  @type PROFILES_PATH: string 
  7   
  8  @author: Peter Parente 
  9  @organization: IBM Corporation 
 10  @copyright: Copyright (c) 2005, 2007 IBM Corporation 
 11   
 12  @author: Frank Zenker 
 13  @author: Ramona Bunk 
 14  @organization: IT Science Center Ruegen gGmbH, Germany 
 15  @copyright: Copyright (c) 2007, 2008 ITSC Ruegen 
 16   
 17  @license: I{The BSD License} 
 18  All rights reserved. This program and the accompanying materials are made 
 19  available under the terms of the BSD license which accompanies 
 20  this distribution, and is available at 
 21  U{http://www.opensource.org/licenses/bsd-license.php} 
 22  ''' 
 23  from SUEConstants import BUILTIN_PROFILES, HOME_USER, initUserPath 
 24  from Tools.i18n import _ 
 25  import shelve, os, shutil, whichdb 
 26   
 27  # paths to parts of the settings repository 
 28  PROFILES_PATH = os.path.join(HOME_USER, 'profiles') 
 29  # make sure the profile folder is available 
 30  if initUserPath(PROFILES_PATH): 
 31    print 'created ~/.sue/profiles' 
 32   
33 -class _AESettingsManager(object):
34 ''' 35 Manages the persistence of Python objects. 36 37 Has methods for loading and saving state under a given name in the profile 38 under which SUE is running or the profile named when the manager is 39 instantiated. Maintains an in-memory cache of some objects loaded from disk 40 to ensure multiple calls to L{load} return the same reference. 41 42 @ivar name: Name of the profile 43 @type name: string 44 @ivar profile: Path to the profile database 45 @type profile: string 46 @ivar cache: Cache of previously loaded state objects. Used to ensure all 47 references returned by L{loadState} point to the same state object. All 48 objects in this cache are persisted to disk when the manager is closed. 49 @type cache: dictionary of string : L{AEState <AEState.AEState>} 50 '''
51 - def __init__(self):
52 ''' 53 Creates the empty cache dictionary for state objects. 54 ''' 55 self.cache = {} 56 # at least one of profile or acc_eng must be specified 57 self.name = None 58 self.profile = None
59
60 - def init(self, profile):
61 ''' 62 Opens the shelved data on disk in the given profile. 63 64 Called by L{AEMain} at startup. 65 66 @param profile: Name of the profile to access using this manager. 67 @type profile: string 68 ''' 69 self.name = profile 70 self.profile = os.path.join(PROFILES_PATH, self.name+'.profile')
71
72 - def close(self):
73 ''' 74 Persists all state in the L{cache}. 75 ''' 76 for name, state in self.cache.items(): 77 self.saveState(name, state)
78
79 - def loadStyles(self, device, default_style, style_cls):
80 ''' 81 Loads a collection of L{AEOutput.Style} objects from disk. 82 83 The loaded styles are not stored in the L{cache} as the singleton 84 requirement does not hold for output device styles. As a result, the styles 85 loaded here will not be automatically persisted when this object is 86 destroyed. L{saveStyles} should be invoked directly. 87 88 @param device: Output device whose style objects we're loading 89 @type device: L{AEOutput <AEOutput.AEOutput>} 90 @param default_style: Instance of a default style object to be populated 91 with data 92 @type default_style: L{AEOutput.Style} 93 @param style_cls: Class for constructing new styles to populate 94 @type style_cls: L{AEOutput.Style} 95 @raise KeyError: When the name is not a valid key 96 @raise OSError: When the profile file cannot be opened or read 97 ''' 98 default_data, styles_data = self.load(device.getClassName()) 99 # get the default style first 100 default_style.unserialize(default_data) 101 flyweight_styles = {} 102 for key, data in styles_data: 103 # build flyweights ontop of the default style 104 st = style_cls(default_style) 105 st.init(device) 106 st.unserialize(data) 107 flyweight_styles[key] = st 108 return flyweight_styles
109
110 - def saveStyles(self, device, default_style, other_styles):
111 ''' 112 Saves the internal data of a collection L{AEOutput.Style} objects to disk. 113 114 @param device: Output device whose style objects we're persisting 115 @type device: L{AEOutput <AEOutput.AEOutput>} 116 @param default_style: Instance of a default style object to have its data 117 persisted 118 @type default_style: L{AEOutput.Style} 119 @param other_styles: Dictionary of other styles to have their data 120 persisted under the keys used in the dictionary 121 @type other_styles: dictionary of immutable : 122 L{AEOutput.Style} 123 @raise OSError: When the profile file cannot be opened or saved 124 ''' 125 flyweight_data = [(key, style.serialize()) for key, style in 126 other_styles.items()] 127 self.save(device.getClassName(), 128 (default_style.serialize(), flyweight_data))
129
130 - def loadState(self, name, state):
131 ''' 132 Loads an L{AEState <AEState.AEState>} object from disk. 133 134 If cached is C{True}, stores a copy of 135 the state to be returned in memory such that future calls to L{load} return 136 the same instance with the same state. 137 138 @param name: Name under which the object was previously stored 139 @type name: string 140 @param state: SUE state object to initialize with the loaded data 141 @type state: L{AEState <AEState.AEState>} 142 @return: Singleton instance of the AEState object for the given name 143 @rtype: L{AEState <AEState.AEState>} 144 @raise KeyError: When the name is not a valid key 145 @raise OSError: When the profile file cannot be opened or read 146 ''' 147 # check the cache first 148 try: 149 return self.cache[name] 150 except KeyError: 151 pass 152 # cache the instance to ensure shared references to state 153 self.cache[name] = state 154 # try to load data for the state object 155 data = self.load(name) 156 # wrap the data in the state object 157 state.unserialize(data) 158 return state
159
160 - def saveState(self, name, state):
161 ''' 162 Saves the internal data of an L{AEState <AEState.AEState>} object to disk. 163 164 Does not Pickle 165 the state object directly, but rather calls its serialize method to get a 166 simple dictionary. This is done to avoid the problems caused by trying to 167 persist state objects in modules that have been reloaded at runtime. Also 168 does not Pickle states that are not dirty according to 169 L{AEState.isDirty <AEState.Base.AEState.isDirty>}. 170 171 @param name: Name under which to save the object 172 @type name: string 173 @param state: SUE state object whose data should be stored 174 @type state: L{AEState <AEState.AEState>} 175 @raise OSError: When the profile file cannot be opened or saved 176 ''' 177 if state.isDirty(): 178 self.save(name, state.serialize())
179
180 - def save(self, name, data):
181 ''' 182 Saves the given object under the given name in the profile used to 183 initialize this manager. 184 185 Pickles the given object without any further 186 processing on the part of this manager. 187 188 @param name: Name under which to save the object 189 @type name: string 190 @param data: Object to store 191 @type data: object 192 @raise OSError: When the profile file cannot be opened or saved 193 ''' 194 db = shelve.open(self.profile, protocol=-1) 195 db[name] = data 196 db.close()
197
198 - def load(self, name):
199 ''' 200 Loads the object from the profile used to initialize the manager. 201 202 Unpickles 203 the object under the given name without any additional processing on the 204 part of this mananger. 205 206 @param name: Name under which the object was previously stored 207 @type name: string 208 @return: Object loaded 209 @rtype: object 210 @raise KeyError: When the name is not a valid key 211 @raise OSError: When the profile file cannot be opened or read 212 ''' 213 db = shelve.open(self.profile, protocol=-1) 214 try: 215 data = db[name] 216 finally: 217 db.close() 218 return data
219
220 - def getProfileName(self):
221 ''' 222 Gets the name of the profile. 223 224 @return: the name of the loaded profile 225 @rtype: string 226 ''' 227 return self.name
228
229 - def createProfile(self):
230 ''' 231 Initializes a new profile on disk. 232 233 @raise ValueError: When the profile already exists 234 @raise OSError: When the profile file cannot be created 235 ''' 236 if self.existsProfile(): 237 raise ValueError(_('Profile %s already exists' % self.name)) 238 db = shelve.open(self.profile, protocol=-1) 239 db.close()
240
241 - def ensureProfile(self):
242 ''' 243 Make sure the managed profile exist on disk. 244 245 @raise ValueError: When the profile does not exist 246 ''' 247 if not self.existsProfile(): 248 raise ValueError(_('Profile %s does not exist') % self.name)
249
250 - def existsProfile(self):
251 ''' 252 Look whether the managed profile exist on disk. 253 254 @return: Does the managed profile exist on disk? 255 @rtype: boolean 256 ''' 257 return whichdb.whichdb(self.profile) is not None
258
259 - def deleteProfile(self):
260 ''' 261 Deletes the managed profile from disk. 262 263 @raise ValueError: When the profile is built-in and cannot be deleted or 264 the profile does not exist 265 @raise OSError: When the profile database cannot be deleted 266 ''' 267 if self.name in BUILTIN_PROFILES: 268 raise ValueError(_('Cannot remove built-in %s profile') % self.name) 269 if not self.existsProfile(): 270 raise ValueError(_('Profile %s does not exist' % self.name)) 271 os.unlink(self.profile)
272
273 - def copyProfile(self, name):
274 ''' 275 Copies this profile to another name on disk. 276 277 This method overwrites the destination if it already exists. 278 279 @param name: Destination profile 280 @type name: string 281 @raise ValueError: When the profile does not exist 282 @raise OSError: When the profile file cannot be copied to the destination 283 ''' 284 if not self.existsProfile(): 285 raise ValueError(_('Profile %s does not exist' % profile_name)) 286 shutil.copy(self.profile, os.path.join(PROFILES_PATH, name+'.profile'))
287 288 @classmethod
289 - def listProfiles(cls):
290 ''' 291 Gets a list of existing profile names. 292 293 @return: List of all profiles stored on disk 294 @rtype: list of string 295 ''' 296 return [name.split(os.extsep)[0] for name in os.listdir(PROFILES_PATH)]
297 298 @classmethod
299 - def hasDefaultProfiles(cls):
300 ''' 301 Gets if the L{SUEConstants.Profile.BUILTIN_PROFILES} exist. 302 303 @todo: RB: The link needs to be reset after the SUEConstants are moved. 304 305 @return: Do the default profiles exist? 306 @rtype: boolean 307 ''' 308 profiles = cls.listProfiles() 309 for name in BUILTIN_PROFILES: 310 if name not in profiles: 311 return False 312 return True
313